├── .gitignore ├── LICENSE ├── README.md ├── UnitTestAnalyzers.sln └── UnitTestAnalyzers ├── UnitTestAnalyzers.Test ├── App.config ├── Design │ └── TestNameMustIncludeMemberUnderTestFunctionalTests.cs ├── Documentation │ └── UseAAACommentsFunctionalTests.cs ├── GlobalSuppressions.cs ├── Helpers │ ├── DiagnosticResult.cs │ └── DiagnosticVerifier.Helper.cs ├── Naming │ ├── UseCorrectTestNameFormatFunctionalTests.cs │ └── UseUnitTestsSuffixFunctionalTests.cs ├── Properties │ └── AssemblyInfo.cs ├── TestData │ ├── TestNameMustIncludeMemberUnderTestAnalyzerMSTestInvalidData.cs │ ├── TestNameMustIncludeMemberUnderTestAnalyzerMSTestValidData.cs │ ├── TestNameMustIncludeMemberUnderTestAnalyzerNUnitTestInvalidData.cs │ ├── TestNameMustIncludeMemberUnderTestAnalyzerNUnitTestValidData.cs │ ├── TestNameMustIncludeMemberUnderTestAnalyzerXunitTestInvalidData.cs │ ├── TestNameMustIncludeMemberUnderTestAnalyzerXunitTestValidData.cs │ ├── TestSettingsData.cs │ ├── UseAAACommentsAnalyzerMSTestInvalidData.cs │ ├── UseAAACommentsAnalyzerMSTestValidData.cs │ ├── UseAAACommentsAnalyzerNUnitTestInvalidData.cs │ ├── UseAAACommentsAnalyzerNUnitTestValidData.cs │ ├── UseAAACommentsAnalyzerXunitTestInvalidData.cs │ ├── UseAAACommentsAnalyzerXunitTestValidData.cs │ ├── UseCorrectTestNameFormatMSTestInvalidData.cs │ ├── UseCorrectTestNameFormatMSTestValidData.cs │ ├── UseCorrectTestNameFormatNUnitTestInvalidData.cs │ ├── UseCorrectTestNameFormatNUnitTestValidData.cs │ ├── UseCorrectTestNameFormatXunitTestInvalidData.cs │ ├── UseCorrectTestNameFormatXunitTestValidData.cs │ ├── UseUnitTestsSuffixMSTestInvalidData.cs │ ├── UseUnitTestsSuffixMSTestValidData.cs │ ├── UseUnitTestsSuffixNUnitTestInvalidData.cs │ ├── UseUnitTestsSuffixNUnitTestValidData.cs │ ├── UseUnitTestsSuffixXunitTestValidData.cs │ └── UseUnitTestsSuffixxUnitTestInvalidData.cs ├── UnitTestAnalyzers.FunctionalTests.csproj ├── Verifiers │ └── DiagnosticVerifier.cs └── packages.config ├── UnitTestAnalyzers.Vsix ├── UnitTestAnalyzers.Vsix.csproj └── source.extension.vsixmanifest └── UnitTestAnalyzers ├── Design └── TestNameMustIncludeMemberUnderTestAnalyzer.cs ├── Documentation └── UseAAACommentsAnalyzer.cs ├── GlobalSuppressions.cs ├── Naming ├── UseCorrectTestNameFormatAnalyzer.cs └── UseUnitTestsSuffixAnalyzer.cs ├── Parsers ├── AttributeBasedTestParser.cs ├── IUnitTestParser.cs ├── MSTestParser.cs ├── NUnitTestParser.cs ├── UnitTestParserFactory.cs └── XUnitTestParser.cs ├── Properties └── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings ├── ObjectModel │ ├── AnalyzersSettings.cs │ ├── SettingsFile.cs │ └── UnitTestFramework.cs ├── SettingsProvider.cs └── SettingsReader.cs ├── UnitTestAnalyzers.csproj └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | 24 | # Visual Studio 2015 cache/options directory 25 | .vs/ 26 | # Uncomment if you have tasks that create the project's static files in wwwroot 27 | #wwwroot/ 28 | 29 | # MSTest test Results 30 | [Tt]est[Rr]esult*/ 31 | [Bb]uild[Ll]og.* 32 | 33 | # NUNIT 34 | *.VisualState.xml 35 | TestResult.xml 36 | 37 | # Build Results of an ATL Project 38 | [Dd]ebugPS/ 39 | [Rr]eleasePS/ 40 | dlldata.c 41 | 42 | # DNX 43 | project.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | # NuGet v3's project.json files produces more ignoreable files 154 | *.nuget.props 155 | *.nuget.targets 156 | 157 | # Microsoft Azure Build Output 158 | csx/ 159 | *.build.csdef 160 | 161 | # Microsoft Azure Emulator 162 | ecf/ 163 | rcf/ 164 | 165 | # Microsoft Azure ApplicationInsights config file 166 | ApplicationInsights.config 167 | 168 | # Windows Store app package directory 169 | AppPackages/ 170 | BundleArtifacts/ 171 | 172 | # Visual Studio cache files 173 | # files ending in .cache can be ignored 174 | *.[Cc]ache 175 | # but keep track of directories ending in .cache 176 | !*.[Cc]ache/ 177 | 178 | # Others 179 | ClientBin/ 180 | ~$* 181 | *~ 182 | *.dbmdl 183 | *.dbproj.schemaview 184 | *.pfx 185 | *.publishsettings 186 | node_modules/ 187 | orleans.codegen.cs 188 | 189 | # RIA/Silverlight projects 190 | Generated_Code/ 191 | 192 | # Backup & report files from converting an old project file 193 | # to a newer Visual Studio version. Backup files are not needed, 194 | # because we have git ;-) 195 | _UpgradeReport_Files/ 196 | Backup*/ 197 | UpgradeLog*.XML 198 | UpgradeLog*.htm 199 | 200 | # SQL Server files 201 | *.mdf 202 | *.ldf 203 | 204 | # Business Intelligence projects 205 | *.rdl.data 206 | *.bim.layout 207 | *.bim_*.settings 208 | 209 | # Microsoft Fakes 210 | FakesAssemblies/ 211 | 212 | # GhostDoc plugin setting file 213 | *.GhostDoc.xml 214 | 215 | # Node.js Tools for Visual Studio 216 | .ntvs_analysis.dat 217 | 218 | # Visual Studio 6 build log 219 | *.plg 220 | 221 | # Visual Studio 6 workspace options file 222 | *.opt 223 | 224 | # Visual Studio LightSwitch build output 225 | **/*.HTMLClient/GeneratedArtifacts 226 | **/*.DesktopClient/GeneratedArtifacts 227 | **/*.DesktopClient/ModelManifest.xml 228 | **/*.Server/GeneratedArtifacts 229 | **/*.Server/ModelManifest.xml 230 | _Pvt_Extensions 231 | 232 | # Paket dependency manager 233 | .paket/paket.exe 234 | 235 | # FAKE - F# Make 236 | .fake/ 237 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Emanoel Xavier 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UnitTestAnalyzers 2 | 3 | [![Join the chat at https://gitter.im/DotNetAnalyzers/UnitTestAnalyzers](https://badges.gitter.im/DotNetAnalyzers/UnitTestAnalyzers.svg)](https://gitter.im/DotNetAnalyzers/UnitTestAnalyzers?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | Analyzers for unit tests using the .NET Compiler Platform 5 | -------------------------------------------------------------------------------- /UnitTestAnalyzers.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestAnalyzers", "UnitTestAnalyzers\UnitTestAnalyzers\UnitTestAnalyzers.csproj", "{F5D899DD-0AD6-4480-A0A8-7B5203D7BE9E}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestAnalyzers.FunctionalTests", "UnitTestAnalyzers\UnitTestAnalyzers.Test\UnitTestAnalyzers.FunctionalTests.csproj", "{B3517669-2026-4681-B5DB-A98C70EE1DA5}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestAnalyzers.Vsix", "UnitTestAnalyzers\UnitTestAnalyzers.Vsix\UnitTestAnalyzers.Vsix.csproj", "{1FB0E60C-FB26-4F04-B766-DFDFCB0EEE5C}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {F5D899DD-0AD6-4480-A0A8-7B5203D7BE9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {F5D899DD-0AD6-4480-A0A8-7B5203D7BE9E}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {F5D899DD-0AD6-4480-A0A8-7B5203D7BE9E}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {F5D899DD-0AD6-4480-A0A8-7B5203D7BE9E}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {B3517669-2026-4681-B5DB-A98C70EE1DA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {B3517669-2026-4681-B5DB-A98C70EE1DA5}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {B3517669-2026-4681-B5DB-A98C70EE1DA5}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {B3517669-2026-4681-B5DB-A98C70EE1DA5}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {1FB0E60C-FB26-4F04-B766-DFDFCB0EEE5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {1FB0E60C-FB26-4F04-B766-DFDFCB0EEE5C}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {1FB0E60C-FB26-4F04-B766-DFDFCB0EEE5C}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {1FB0E60C-FB26-4F04-B766-DFDFCB0EEE5C}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/Design/TestNameMustIncludeMemberUnderTestFunctionalTests.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.Design 2 | { 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Microsoft.CodeAnalysis.Diagnostics; 6 | using Settings.ObjectModel; 7 | using TestData; 8 | using TestHelper; 9 | using Xunit; 10 | 11 | public class TestNameMustIncludeMemberUnderTestFunctionalTests : DiagnosticVerifier 12 | { 13 | private string settings; 14 | 15 | [Theory] 16 | [ClassData(typeof(TestNameMustIncludeMemberUnderTestAnalyzerMSTestInvalidData))] 17 | public async Task IncludeMemberUnderTestInTestName_MSTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testMethodName, string testMethodNameMemberUnderTest, int violantioLine, int violationColumn, string settings) 18 | { 19 | this.settings = settings; 20 | DiagnosticResult expected = this.CSharpDiagnostic().WithArguments(testMethodName, testMethodNameMemberUnderTest).WithLocation(violantioLine, violationColumn); 21 | await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false); 22 | } 23 | 24 | [Theory] 25 | [ClassData(typeof(TestNameMustIncludeMemberUnderTestAnalyzerXunitTestInvalidData))] 26 | public async Task IncludeMemberUnderTestInTestName_XunitTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testMethodName, string testMethodNameMemberUnderTest, int violantioLine, int violationColumn, string settings) 27 | { 28 | this.settings = settings; 29 | DiagnosticResult expected = this.CSharpDiagnostic().WithArguments(testMethodName, testMethodNameMemberUnderTest).WithLocation(violantioLine, violationColumn); 30 | await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None, UnitTestFramework.Xunit).ConfigureAwait(false); 31 | } 32 | 33 | [Theory] 34 | [ClassData(typeof(TestNameMustIncludeMemberUnderTestAnalyzerNUnitTestInvalidData))] 35 | public async Task IncludeMemberUnderTestInTestName_NUnitTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testMethodName, string testMethodNameMemberUnderTest, int violantioLine, int violationColumn, string settings) 36 | { 37 | this.settings = settings; 38 | DiagnosticResult expected = this.CSharpDiagnostic().WithArguments(testMethodName, testMethodNameMemberUnderTest).WithLocation(violantioLine, violationColumn); 39 | await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None, UnitTestFramework.NUnit).ConfigureAwait(false); 40 | } 41 | 42 | [Theory] 43 | [ClassData(typeof(TestNameMustIncludeMemberUnderTestAnalyzerMSTestValidData))] 44 | public async Task IncludeMemberUnderTestInTestName_MSTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 45 | { 46 | this.settings = settings; 47 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); 48 | } 49 | 50 | [Theory] 51 | [ClassData(typeof(TestNameMustIncludeMemberUnderTestAnalyzerXunitTestValidData))] 52 | public async Task IncludeMemberUnderTestInTestName_XunitTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 53 | { 54 | this.settings = settings; 55 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None, UnitTestFramework.Xunit).ConfigureAwait(false); 56 | } 57 | 58 | [Theory] 59 | [ClassData(typeof(TestNameMustIncludeMemberUnderTestAnalyzerNUnitTestValidData))] 60 | public async Task IncludeMemberUnderTestInTestName_NUnitTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 61 | { 62 | this.settings = settings; 63 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None, UnitTestFramework.NUnit).ConfigureAwait(false); 64 | } 65 | 66 | /// 67 | /// Get the CSharp analyzer being tested. 68 | /// 69 | protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() 70 | { 71 | return new TestNameMustIncludeMemberUnderTestAnalyzer(); 72 | } 73 | 74 | /// 75 | protected override string GetSettings() 76 | { 77 | return this.settings; 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/Documentation/UseAAACommentsFunctionalTests.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.Documentation 2 | { 3 | using System.Collections.Generic; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Microsoft.CodeAnalysis.Diagnostics; 7 | using Settings.ObjectModel; 8 | using TestData; 9 | using TestHelper; 10 | using Xunit; 11 | 12 | public class UseAAACommentsFunctionalTests : DiagnosticVerifier 13 | { 14 | private string settings; 15 | 16 | [Theory] 17 | [ClassData(typeof(UseAAACommentsAnalyzerMSTestInvalidData))] 18 | public async Task UseAAAComments_MSTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testMethodName, int violantioLine, int violationColumn, string settings, bool hasValidAAAComments, bool firstLineIsArrangeComment) 19 | { 20 | this.settings = settings; 21 | var expectedDiagnostics = new List(); 22 | if (!hasValidAAAComments) 23 | { 24 | expectedDiagnostics.Add(this.CSharpDiagnostic(UseAAACommentsAnalyzer.AAACommentsDiagnosticId).WithArguments(testMethodName).WithLocation(violantioLine, violationColumn)); 25 | } 26 | 27 | if (!firstLineIsArrangeComment) 28 | { 29 | expectedDiagnostics.Add(this.CSharpDiagnostic(UseAAACommentsAnalyzer.ArrangeCommentFirstLineDiagnosticId).WithArguments(testMethodName).WithLocation(violantioLine, violationColumn)); 30 | } 31 | 32 | await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostics.ToArray(), CancellationToken.None).ConfigureAwait(false); 33 | } 34 | 35 | [Theory] 36 | [ClassData(typeof(UseAAACommentsAnalyzerXunitTestInvalidData))] 37 | public async Task UseAAAComments_XunitTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testMethodName, int violantioLine, int violationColumn, string settings, bool hasValidAAAComments, bool firstLineIsArrangeComment) 38 | { 39 | this.settings = settings; 40 | var expectedDiagnostics = new List(); 41 | if (!hasValidAAAComments) 42 | { 43 | expectedDiagnostics.Add(this.CSharpDiagnostic(UseAAACommentsAnalyzer.AAACommentsDiagnosticId).WithArguments(testMethodName).WithLocation(violantioLine, violationColumn)); 44 | } 45 | 46 | if (!firstLineIsArrangeComment) 47 | { 48 | expectedDiagnostics.Add(this.CSharpDiagnostic(UseAAACommentsAnalyzer.ArrangeCommentFirstLineDiagnosticId).WithArguments(testMethodName).WithLocation(violantioLine, violationColumn)); 49 | } 50 | 51 | await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostics.ToArray(), CancellationToken.None, UnitTestFramework.Xunit).ConfigureAwait(false); 52 | } 53 | 54 | [Theory] 55 | [ClassData(typeof(UseAAACommentsAnalyzerNUnitTestInvalidData))] 56 | public async Task UseAAAComments_NUnitTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testMethodName, int violantioLine, int violationColumn, string settings, bool hasValidAAAComments, bool firstLineIsArrangeComment) 57 | { 58 | this.settings = settings; 59 | var expectedDiagnostics = new List(); 60 | if (!hasValidAAAComments) 61 | { 62 | expectedDiagnostics.Add(this.CSharpDiagnostic(UseAAACommentsAnalyzer.AAACommentsDiagnosticId).WithArguments(testMethodName).WithLocation(violantioLine, violationColumn)); 63 | } 64 | 65 | if (!firstLineIsArrangeComment) 66 | { 67 | expectedDiagnostics.Add(this.CSharpDiagnostic(UseAAACommentsAnalyzer.ArrangeCommentFirstLineDiagnosticId).WithArguments(testMethodName).WithLocation(violantioLine, violationColumn)); 68 | } 69 | 70 | await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostics.ToArray(), CancellationToken.None, UnitTestFramework.NUnit).ConfigureAwait(false); 71 | } 72 | 73 | [Theory] 74 | [ClassData(typeof(UseAAACommentsAnalyzerMSTestValidData))] 75 | public async Task UseAAAComments_MSTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 76 | { 77 | this.settings = settings; 78 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); 79 | } 80 | 81 | [Theory] 82 | [ClassData(typeof(UseAAACommentsAnalyzerXunitTestValidData))] 83 | public async Task UseAAAComments_XunitTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 84 | { 85 | this.settings = settings; 86 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None, UnitTestFramework.Xunit).ConfigureAwait(false); 87 | } 88 | 89 | [Theory] 90 | [ClassData(typeof(UseAAACommentsAnalyzerNUnitTestValidData))] 91 | public async Task UseAAAComments_NUnitTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 92 | { 93 | this.settings = settings; 94 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None, UnitTestFramework.NUnit).ConfigureAwait(false); 95 | } 96 | 97 | /// 98 | /// Get the CSharp analyzer being tested. 99 | /// 100 | protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() 101 | { 102 | return new UseAAACommentsAnalyzer(); 103 | } 104 | 105 | /// 106 | protected override string GetSettings() 107 | { 108 | return this.settings; 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | 6 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:File must have header", Justification = "")] 7 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements must be documented", Justification = "")] 8 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1615:Element return value must be documented", Justification = "")] 9 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1652:Enable XML documentation output", Justification = "")] 10 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("AsyncUsage.CSharp.Naming", "UseAsyncSuffix:Use Async suffix", Justification = "")] -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/Helpers/DiagnosticResult.cs: -------------------------------------------------------------------------------- 1 | namespace TestHelper 2 | { 3 | using System; 4 | using Microsoft.CodeAnalysis; 5 | 6 | /// 7 | /// Struct that stores information about a Diagnostic appearing in a source 8 | /// 9 | public struct DiagnosticResult 10 | { 11 | private static readonly object[] EmptyArguments = new object[0]; 12 | private DiagnosticResultLocation[] locations; 13 | private string message; 14 | 15 | internal DiagnosticResult(DiagnosticDescriptor descriptor) 16 | : this() 17 | { 18 | this.Id = descriptor.Id; 19 | this.Severity = descriptor.DefaultSeverity; 20 | this.MessageFormat = descriptor.MessageFormat; 21 | } 22 | 23 | internal DiagnosticResultLocation[] Locations 24 | { 25 | get 26 | { 27 | if (this.locations == null) 28 | { 29 | this.locations = new DiagnosticResultLocation[] { }; 30 | } 31 | 32 | return this.locations; 33 | } 34 | 35 | set 36 | { 37 | this.locations = value; 38 | } 39 | } 40 | 41 | internal LocalizableString MessageFormat 42 | { 43 | get; 44 | set; 45 | } 46 | 47 | internal DiagnosticSeverity Severity { get; set; } 48 | 49 | internal string Id { get; set; } 50 | 51 | internal string Message 52 | { 53 | get 54 | { 55 | if (this.message != null) 56 | { 57 | return this.message; 58 | } 59 | 60 | if (this.MessageFormat != null) 61 | { 62 | return string.Format(this.MessageFormat.ToString(), this.MessageArguments ?? EmptyArguments); 63 | } 64 | 65 | return null; 66 | } 67 | 68 | set 69 | { 70 | this.message = value; 71 | } 72 | } 73 | 74 | internal string Path 75 | { 76 | get 77 | { 78 | return this.Locations.Length > 0 ? this.Locations[0].Path : string.Empty; 79 | } 80 | } 81 | 82 | internal object[] MessageArguments 83 | { 84 | get; 85 | set; 86 | } 87 | 88 | internal int Line 89 | { 90 | get 91 | { 92 | return this.Locations.Length > 0 ? this.Locations[0].Line : -1; 93 | } 94 | } 95 | 96 | internal int Column 97 | { 98 | get 99 | { 100 | return this.Locations.Length > 0 ? this.Locations[0].Column : -1; 101 | } 102 | } 103 | 104 | public DiagnosticResult WithArguments(params object[] arguments) 105 | { 106 | DiagnosticResult result = this; 107 | result.MessageArguments = arguments; 108 | return result; 109 | } 110 | 111 | public DiagnosticResult WithLocation(int line, int column) 112 | { 113 | return this.WithLocation("Test0.cs", line, column); 114 | } 115 | 116 | public DiagnosticResult WithLocation(string path, int line, int column) 117 | { 118 | DiagnosticResult result = this; 119 | Array.Resize(ref result.locations, (result.locations?.Length ?? 0) + 1); 120 | result.locations[result.locations.Length - 1] = new DiagnosticResultLocation(path, line, column); 121 | return result; 122 | } 123 | } 124 | 125 | /// 126 | /// Location where the diagnostic appears, as determined by path, line number, and column number. 127 | /// 128 | internal struct DiagnosticResultLocation 129 | { 130 | internal DiagnosticResultLocation(string path, int line, int column) 131 | { 132 | if (line < -1) 133 | { 134 | throw new ArgumentOutOfRangeException(nameof(line), "line must be >= -1"); 135 | } 136 | 137 | if (column < -1) 138 | { 139 | throw new ArgumentOutOfRangeException(nameof(column), "column must be >= -1"); 140 | } 141 | 142 | this.Path = path; 143 | this.Line = line; 144 | this.Column = column; 145 | } 146 | 147 | internal string Path { get; } 148 | 149 | internal int Line { get; } 150 | 151 | internal int Column { get; } 152 | } 153 | } -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/Naming/UseCorrectTestNameFormatFunctionalTests.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.Naming 2 | { 3 | using Xunit; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Microsoft.CodeAnalysis.Diagnostics; 7 | using Settings.ObjectModel; 8 | using TestData; 9 | using TestHelper; 10 | 11 | public class UseCorrectTestNameFormatFunctionalTests : DiagnosticVerifier 12 | { 13 | private string settings; 14 | 15 | [Theory] 16 | [ClassData(typeof(UseCorrectTestNameFormatMSTestInvalidData))] 17 | public async Task UseCorrectTestNameFormat_MSTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testMethodName, int violantioLine, int violationColumn, string settings, string testMethodFormat, string[] testMethodNameExamples) 18 | { 19 | this.settings = settings; 20 | string testMethodNameExamplesArgument = string.Join(", ", testMethodNameExamples); 21 | DiagnosticResult expected = this.CSharpDiagnostic().WithArguments(testMethodName, testMethodFormat, testMethodNameExamplesArgument).WithLocation(violantioLine, violationColumn); 22 | await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false); 23 | } 24 | 25 | [Theory] 26 | [ClassData(typeof(UseCorrectTestNameFormatMSTestValidData))] 27 | public async Task UseCorrectTestNameFormat_MSTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 28 | { 29 | this.settings = settings; 30 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); 31 | } 32 | 33 | [Theory] 34 | [ClassData(typeof(UseCorrectTestNameFormatXunitTestInvalidData))] 35 | public async Task UseCorrectTestNameFormat_XunitTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testMethodName, int violantioLine, int violationColumn, string settings, string testMethodFormat, string[] testMethodNameExamples) 36 | { 37 | this.settings = settings; 38 | string testMethodNameExamplesArgument = string.Join(", ", testMethodNameExamples); 39 | DiagnosticResult expected = this.CSharpDiagnostic().WithArguments(testMethodName, testMethodFormat, testMethodNameExamplesArgument).WithLocation(violantioLine, violationColumn); 40 | await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None, UnitTestFramework.Xunit).ConfigureAwait(false); 41 | } 42 | 43 | [Theory] 44 | [ClassData(typeof(UseCorrectTestNameFormatXunitTestValidData))] 45 | public async Task UseCorrectTestNameFormat_UsingxUnitTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 46 | { 47 | this.settings = settings; 48 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None, UnitTestFramework.Xunit).ConfigureAwait(false); 49 | } 50 | 51 | [Theory] 52 | [ClassData(typeof(UseCorrectTestNameFormatNUnitTestInvalidData))] 53 | public async Task UseCorrectTestNameFormat_NUnitTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testMethodName, int violantioLine, int violationColumn, string settings, string testMethodFormat, string[] testMethodNameExamples) 54 | { 55 | this.settings = settings; 56 | string testMethodNameExamplesArgument = string.Join(", ", testMethodNameExamples); 57 | DiagnosticResult expected = this.CSharpDiagnostic().WithArguments(testMethodName, testMethodFormat, testMethodNameExamplesArgument).WithLocation(violantioLine, violationColumn); 58 | await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None, UnitTestFramework.NUnit).ConfigureAwait(false); 59 | } 60 | 61 | [Theory] 62 | [ClassData(typeof(UseCorrectTestNameFormatNUnitTestValidData))] 63 | public async Task UseCorrectTestNameFormat_UsingNUnitTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 64 | { 65 | this.settings = settings; 66 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None, UnitTestFramework.NUnit).ConfigureAwait(false); 67 | } 68 | 69 | /// 70 | /// Get the CSharp analyzer being tested. 71 | /// 72 | protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() 73 | { 74 | return new UseCorrectTestNameFormatAnalyzer(); 75 | } 76 | 77 | /// 78 | protected override string GetSettings() 79 | { 80 | return this.settings; 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/Naming/UseUnitTestsSuffixFunctionalTests.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.Naming 2 | { 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Microsoft.CodeAnalysis.Diagnostics; 6 | using Settings.ObjectModel; 7 | using TestData; 8 | using TestHelper; 9 | using Xunit; 10 | 11 | public class UseUnitTestsSuffixFunctionalTests : DiagnosticVerifier 12 | { 13 | private string settings; 14 | 15 | [Theory] 16 | [ClassData(typeof(UseUnitTestsSuffixMSTestValidData))] 17 | public async Task UseUnitTestsSuffix_MSTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 18 | { 19 | this.settings = settings; 20 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); 21 | } 22 | 23 | [Theory] 24 | [ClassData(typeof(UseUnitTestsSuffixMSTestInvalidData))] 25 | public async Task UseUnitTestsSuffix_MSTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testClassName, int violantioLine, int violationColumn, string settings) 26 | { 27 | this.settings = settings; 28 | DiagnosticResult expected = this.CSharpDiagnostic().WithArguments(testClassName).WithLocation(violantioLine, violationColumn); 29 | await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false); 30 | } 31 | 32 | [Theory] 33 | [ClassData(typeof(UseUnitTestsSuffixXunitTestValidData))] 34 | public async Task UseUnitTestsSuffix_xUnitTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 35 | { 36 | this.settings = settings; 37 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None, UnitTestFramework.Xunit).ConfigureAwait(false); 38 | } 39 | 40 | [Theory] 41 | [ClassData(typeof(UseUnitTestsSuffixXunitTestInvalidData))] 42 | public async Task UseUnitTestsSuffix_xUnitTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testClassName, int violantionLine, int violationColumn, string settings) 43 | { 44 | this.settings = settings; 45 | DiagnosticResult expected = this.CSharpDiagnostic().WithArguments(testClassName).WithLocation(violantionLine, violationColumn); 46 | await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None, UnitTestFramework.Xunit).ConfigureAwait(false); 47 | } 48 | 49 | [Theory] 50 | [ClassData(typeof(UseUnitTestsSuffixNUnitTestValidData))] 51 | public async Task UseUnitTestsSuffix_NUnitTestCodeWithoutViolation_ExpectsNoDiagnostic(string testCode, string settings) 52 | { 53 | this.settings = settings; 54 | await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None, UnitTestFramework.NUnit).ConfigureAwait(false); 55 | } 56 | 57 | [Theory] 58 | [ClassData(typeof(UseUnitTestsSuffixNUnitTestInvalidData))] 59 | public async Task UseUnitTestsSuffix_NUnitTestCodeWithViolation_ExpectsDiagnostic(string testCode, string testClassName, int violantionLine, int violationColumn, string settings) 60 | { 61 | this.settings = settings; 62 | DiagnosticResult expected = this.CSharpDiagnostic().WithArguments(testClassName).WithLocation(violantionLine, violationColumn); 63 | await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None, UnitTestFramework.NUnit).ConfigureAwait(false); 64 | } 65 | 66 | protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() 67 | { 68 | return new UseUnitTestsSuffixAnalyzer(); 69 | } 70 | 71 | protected override string GetSettings() 72 | { 73 | return this.settings; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("UnitTestAnalyzers.Test")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("UnitTestAnalyzers.Test")] 12 | [assembly: AssemblyCopyright("Copyright © 2016")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // Version information for an assembly consists of the following four values: 22 | // 23 | // Major Version 24 | // Minor Version 25 | // Build Number 26 | // Revision 27 | // 28 | // You can specify all the values or you can default the Build and Revision Numbers 29 | // by using the '*' as shown below: 30 | // [assembly: AssemblyVersion("1.0.*")] 31 | [assembly: AssemblyVersion("1.0.0.0")] 32 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/TestNameMustIncludeMemberUnderTestAnalyzerMSTestInvalidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class TestNameMustIncludeMemberUnderTestAnalyzerMSTestInvalidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // A test method targeting a constructor does not have its first part matching the name of the constructor under test. 11 | yield return new object[] 12 | { 13 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 14 | class RegexUnitTests 15 | { 16 | [TestMethod] 17 | public void TestCtor_UsingNullString_ThrowsArgumentNullException() 18 | { 19 | Regex r = new Regex(null); 20 | } 21 | }", 22 | "TestCtor_UsingNullString_ThrowsArgumentNullException", // Diagnostic message paramater 23 | "TestCtor", // Diagnostic message parameter 24 | 5, // Violation line 25 | 13, // Violation column. 26 | TestSettingsData.NoSettings 27 | }; 28 | 29 | // A test method targeting a property does not have its first part matching the name of the property under test. 30 | yield return new object[] 31 | { 32 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 33 | class RegexUnitTests 34 | { 35 | [TestMethod] 36 | public void TestProperty_WhenOptionsIsNotProvided_ExpectsRetrievedOptionsEmpty() 37 | { 38 | Regex r = new Regex(""regex""); 39 | var options = r.Options; 40 | } 41 | }", 42 | "TestProperty_WhenOptionsIsNotProvided_ExpectsRetrievedOptionsEmpty", 43 | "TestProperty", 44 | 5, 45 | 13, 46 | TestSettingsData.NoSettings 47 | }; 48 | 49 | // A test method targeting a method does not have its first part matching the name of the method under test. 50 | yield return new object[] 51 | { 52 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 53 | class RegexUnitTests 54 | { 55 | [TestMethod] 56 | public void TestMethod_UsingNonMatchingString_ExpectsFalse() 57 | { 58 | Regex r = new Regex(""regex""); 59 | var result = r.IsMatch(""Foo""); 60 | } 61 | }", 62 | "TestMethod_UsingNonMatchingString_ExpectsFalse", 63 | "TestMethod", 64 | 5, 65 | 13, 66 | TestSettingsData.NoSettings 67 | }; 68 | 69 | // A test method targeting a method does not have its first part matching the name of the method under test. 70 | // Instead that part matches the name of a variable within the test body. 71 | yield return new object[] 72 | { 73 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 74 | class RegexUnitTests 75 | { 76 | [TestMethod] 77 | public void result_UsingNonMatchingString_ExpectsFalse() 78 | { 79 | Regex r = new Regex(""regex""); 80 | var result = r.IsMatch(""Foo""); 81 | } 82 | }", 83 | "result_UsingNonMatchingString_ExpectsFalse", 84 | "result", 85 | 5, 86 | 13, 87 | TestSettingsData.NoSettings 88 | }; 89 | 90 | // A test method targeting a method does not have its first part matching the name of the method under test. 91 | // Instead that part matches the name of a parameter within the test body. 92 | yield return new object[] 93 | { 94 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 95 | class RegexUnitTests 96 | { 97 | [TestMethod] 98 | public void Foo_UsingNonMatchingString_ExpectsFalse() 99 | { 100 | Regex r = new Regex(""regex""); 101 | var result = r.IsMatch(""Foo""); 102 | } 103 | }", 104 | "Foo_UsingNonMatchingString_ExpectsFalse", 105 | "Foo", 106 | 5, 107 | 13, 108 | TestSettingsData.NoSettings 109 | }; 110 | 111 | // A test method targeting a method does not have its first part matching the name of the method under test. 112 | // Instead that part matches a comment withing the method body. 113 | yield return new object[] 114 | { 115 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 116 | class RegexUnitTests 117 | { 118 | [TestMethod] 119 | public void Init_UsingNonMatchingString_ExpectsFalse() 120 | { 121 | // Init. 122 | Regex r = new Regex(""regex""); 123 | var result = r.IsMatch(""Foo""); 124 | } 125 | }", 126 | "Init_UsingNonMatchingString_ExpectsFalse", 127 | "Init", 128 | 5, 129 | 13, 130 | TestSettingsData.NoSettings 131 | }; 132 | 133 | // A test method name not have its member under test part matching the name of the method under test. 134 | // The analyzer settings provides a new regex that defines a group named 'memberUnderTestName'. 135 | yield return new object[] 136 | { 137 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 138 | class RegexUnitTests 139 | { 140 | [TestMethod] 141 | public void TestFoo_Method() 142 | { 143 | Regex r = new Regex(""regex""); 144 | var result = r.IsMatch(""Foo""); 145 | } 146 | }", 147 | "TestFoo_Method", 148 | "Method", 149 | 5, 150 | 13, 151 | TestSettingsData.MSTestSettingsMemberUnderTestRegexFormat 152 | }; 153 | } 154 | 155 | IEnumerator IEnumerable.GetEnumerator() 156 | { 157 | return this.GetEnumerator(); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/TestNameMustIncludeMemberUnderTestAnalyzerMSTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class TestNameMustIncludeMemberUnderTestAnalyzerMSTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // The test method name does not match the Regex pattern in the member under test group. 11 | yield return new object[] 12 | { 13 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 14 | class RegexUnitTests 15 | { 16 | [TestMethod] 17 | public void TestCtor!_UsingNullString_ThrowsArgumentNullException() 18 | { 19 | Regex r = new Regex(null); 20 | } 21 | }", 22 | TestSettingsData.NoSettings 23 | }; 24 | 25 | // The test method with empty body. 26 | yield return new object[] 27 | { 28 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 29 | class RegexUnitTests 30 | { 31 | [TestMethod] 32 | public void TestMethod_UsingNullString_ThrowsArgumentNullException() 33 | { 34 | } 35 | }", 36 | TestSettingsData.NoSettings 37 | }; 38 | 39 | // The test method with body containing comments only. 40 | yield return new object[] 41 | { 42 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 43 | class RegexUnitTests 44 | { 45 | [TestMethod] 46 | public void TestMethod_UsingNullString_ThrowsArgumentNullException() 47 | { 48 | // Comment. 49 | } 50 | }", 51 | TestSettingsData.NoSettings 52 | }; 53 | 54 | // The test method with body containing a variable declaration only. 55 | yield return new object[] 56 | { 57 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 58 | class RegexUnitTests 59 | { 60 | [TestMethod] 61 | public void TestMethod_UsingNullString_ThrowsArgumentNullException() 62 | { 63 | string str = ""foo"" 64 | } 65 | }", 66 | TestSettingsData.NoSettings 67 | }; 68 | 69 | // The test method name does not match the Regex pattern in another part of the name. 70 | yield return new object[] 71 | { 72 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 73 | class RegexUnitTests 74 | { 75 | [TestMethod] 76 | public void TestCtor_NullString_ThrowsArgumentNullException() 77 | { 78 | Regex r = new Regex(null); 79 | } 80 | }", 81 | TestSettingsData.NoSettings 82 | }; 83 | 84 | // A test method targeting a constructor hase its first part matching the name of the constructor under test. 85 | yield return new object[] 86 | { 87 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 88 | class RegexUnitTests 89 | { 90 | [TestMethod] 91 | public void Regex_UsingNullString_ThrowsArgumentNullException() 92 | { 93 | Regex r = new Regex(null); 94 | } 95 | }", 96 | TestSettingsData.NoSettings 97 | }; 98 | 99 | // A test method targeting a property has its first part matching the name of the property under test. 100 | yield return new object[] 101 | { 102 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 103 | class RegexUnitTests 104 | { 105 | [TestMethod] 106 | public void Options_WhenOptionsIsNotProvided_ExpectsRetrievedOptionsEmpty() 107 | { 108 | Regex r = new Regex(""regex""); 109 | var options = r.Options; 110 | } 111 | }", 112 | TestSettingsData.NoSettings 113 | }; 114 | 115 | // A test method targeting a method has its first part matching the name of the method under test. 116 | yield return new object[] 117 | { 118 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 119 | class RegexUnitTests 120 | { 121 | [TestMethod] 122 | public void IsMatch_UsingNonMatchingString_ExpectsFalse() 123 | { 124 | Regex r = new Regex(""regex""); 125 | var result = r.IsMatch(""Foo""); 126 | } 127 | }", 128 | TestSettingsData.NoSettings 129 | }; 130 | 131 | // A test method name has its member under test part matching the name of the method under test. 132 | // The analyzer settings provides a new regex that defines a group named 'memberUnderTestName'. 133 | yield return new object[] 134 | { 135 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 136 | class RegexUnitTests 137 | { 138 | [TestMethod] 139 | public void TestFoo_IsMatch() 140 | { 141 | Regex r = new Regex(""regex""); 142 | var result = r.IsMatch(""Foo""); 143 | } 144 | }", 145 | TestSettingsData.MSTestSettingsMemberUnderTestRegexFormat 146 | }; 147 | } 148 | 149 | IEnumerator IEnumerable.GetEnumerator() 150 | { 151 | return this.GetEnumerator(); 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/TestNameMustIncludeMemberUnderTestAnalyzerNUnitTestInvalidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class TestNameMustIncludeMemberUnderTestAnalyzerNUnitTestInvalidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // A test method targeting a constructor does not have its first part matching the name of the constructor under test. 11 | yield return new object[] 12 | { 13 | @"using NUnit.Framework; 14 | class RegexUnitTests 15 | { 16 | [Test] 17 | public void TestCtor_UsingNullString_ThrowsArgumentNullException() 18 | { 19 | Regex r = new Regex(null); 20 | } 21 | }", 22 | "TestCtor_UsingNullString_ThrowsArgumentNullException", // Diagnostic message paramater 23 | "TestCtor", // Diagnostic message parameter 24 | 5, // Violation line 25 | 13, // Violation column. 26 | TestSettingsData.NUnitSettings 27 | }; 28 | 29 | // A test method targeting a property does not have its first part matching the name of the property under test. 30 | yield return new object[] 31 | { 32 | @"using NUnit.Framework; 33 | class RegexUnitTests 34 | { 35 | [Test] 36 | public void TestProperty_WhenOptionsIsNotProvided_ExpectsRetrievedOptionsEmpty() 37 | { 38 | Regex r = new Regex(""regex""); 39 | var options = r.Options; 40 | } 41 | }", 42 | "TestProperty_WhenOptionsIsNotProvided_ExpectsRetrievedOptionsEmpty", 43 | "TestProperty", 44 | 5, 45 | 13, 46 | TestSettingsData.NUnitSettings 47 | }; 48 | 49 | // A test method targeting a method does not have its first part matching the name of the method under test. 50 | yield return new object[] 51 | { 52 | @"using NUnit.Framework; 53 | class RegexUnitTests 54 | { 55 | [Test] 56 | public void TestMethod_UsingNonMatchingString_ExpectsFalse() 57 | { 58 | Regex r = new Regex(""regex""); 59 | var result = r.IsMatch(""Foo""); 60 | } 61 | }", 62 | "TestMethod_UsingNonMatchingString_ExpectsFalse", 63 | "TestMethod", 64 | 5, 65 | 13, 66 | TestSettingsData.NUnitSettings 67 | }; 68 | 69 | // A test method targeting a method does not have its first part matching the name of the method under test. 70 | // Instead that part matches the name of a variable within the test body. 71 | yield return new object[] 72 | { 73 | @"using NUnit.Framework; 74 | class RegexUnitTests 75 | { 76 | [Test] 77 | public void result_UsingNonMatchingString_ExpectsFalse() 78 | { 79 | Regex r = new Regex(""regex""); 80 | var result = r.IsMatch(""Foo""); 81 | } 82 | }", 83 | "result_UsingNonMatchingString_ExpectsFalse", 84 | "result", 85 | 5, 86 | 13, 87 | TestSettingsData.NUnitSettings 88 | }; 89 | 90 | // A test method targeting a method does not have its first part matching the name of the method under test. 91 | // Instead that part matches the name of a parameter within the test body. 92 | yield return new object[] 93 | { 94 | @"using NUnit.Framework; 95 | class RegexUnitTests 96 | { 97 | [Test] 98 | public void Foo_UsingNonMatchingString_ExpectsFalse() 99 | { 100 | Regex r = new Regex(""regex""); 101 | var result = r.IsMatch(""Foo""); 102 | } 103 | }", 104 | "Foo_UsingNonMatchingString_ExpectsFalse", 105 | "Foo", 106 | 5, 107 | 13, 108 | TestSettingsData.NUnitSettings 109 | }; 110 | 111 | // A test method targeting a method does not have its first part matching the name of the method under test. 112 | // Instead that part matches a comment withing the method body. 113 | yield return new object[] 114 | { 115 | @"using NUnit.Framework; 116 | class RegexUnitTests 117 | { 118 | [Test] 119 | public void Init_UsingNonMatchingString_ExpectsFalse() 120 | { 121 | // Init. 122 | Regex r = new Regex(""regex""); 123 | var result = r.IsMatch(""Foo""); 124 | } 125 | }", 126 | "Init_UsingNonMatchingString_ExpectsFalse", 127 | "Init", 128 | 5, 129 | 13, 130 | TestSettingsData.NUnitSettings 131 | }; 132 | 133 | // A test method name not have its member under test part matching the name of the method under test. 134 | // The analyzer settings provides a new regex that defines a group named 'memberUnderTestName'. 135 | yield return new object[] 136 | { 137 | @"using NUnit.Framework; 138 | class RegexUnitTests 139 | { 140 | [Test] 141 | public void TestFoo_Method() 142 | { 143 | Regex r = new Regex(""regex""); 144 | var result = r.IsMatch(""Foo""); 145 | } 146 | }", 147 | "TestFoo_Method", 148 | "Method", 149 | 5, 150 | 13, 151 | TestSettingsData.NUnitTestSettingsMemberUnderTestRegexFormat 152 | }; 153 | } 154 | 155 | IEnumerator IEnumerable.GetEnumerator() 156 | { 157 | return this.GetEnumerator(); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/TestNameMustIncludeMemberUnderTestAnalyzerNUnitTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class TestNameMustIncludeMemberUnderTestAnalyzerNUnitTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // The test method name does not match the Regex pattern in the member under test group. 11 | yield return new object[] 12 | { 13 | @"using NUnit.Framework; 14 | class RegexUnitTests 15 | { 16 | [Test] 17 | public void TestCtor!_UsingNullString_ThrowsArgumentNullException() 18 | { 19 | Regex r = new Regex(null); 20 | } 21 | }", 22 | TestSettingsData.NUnitSettings 23 | }; 24 | 25 | // The test method with empty body. 26 | yield return new object[] 27 | { 28 | @"using NUnit.Framework; 29 | class RegexUnitTests 30 | { 31 | [Test] 32 | public void TestMethod_UsingNullString_ThrowsArgumentNullException() 33 | { 34 | } 35 | }", 36 | TestSettingsData.NUnitSettings 37 | }; 38 | 39 | // The test method with body containing comments only. 40 | yield return new object[] 41 | { 42 | @"using NUnit.Framework; 43 | class RegexUnitTests 44 | { 45 | [Test] 46 | public void TestMethod_UsingNullString_ThrowsArgumentNullException() 47 | { 48 | // Comment. 49 | } 50 | }", 51 | TestSettingsData.NUnitSettings 52 | }; 53 | 54 | // The test method with body containing a variable declaration only. 55 | yield return new object[] 56 | { 57 | @"using NUnit.Framework; 58 | class RegexUnitTests 59 | { 60 | [Test] 61 | public void TestMethod_UsingNullString_ThrowsArgumentNullException() 62 | { 63 | string str = ""foo"" 64 | } 65 | }", 66 | TestSettingsData.NUnitSettings 67 | }; 68 | 69 | // The test method name does not match the Regex pattern in another part of the name. 70 | yield return new object[] 71 | { 72 | @"using NUnit.Framework; 73 | class RegexUnitTests 74 | { 75 | [Test] 76 | public void TestCtor_NullString_ThrowsArgumentNullException() 77 | { 78 | Regex r = new Regex(null); 79 | } 80 | }", 81 | TestSettingsData.NUnitSettings 82 | }; 83 | 84 | // A test method targeting a constructor has its first part matching the name of the constructor under test. 85 | yield return new object[] 86 | { 87 | @"using NUnit.Framework; 88 | class RegexUnitTests 89 | { 90 | [Test] 91 | public void Regex_UsingNullString_ThrowsArgumentNullException() 92 | { 93 | Regex r = new Regex(null); 94 | } 95 | }", 96 | TestSettingsData.NUnitSettings 97 | }; 98 | 99 | // A test method targeting a property has its first part matching the name of the property under test. 100 | yield return new object[] 101 | { 102 | @"using NUnit.Framework; 103 | class RegexUnitTests 104 | { 105 | [Test] 106 | public void Options_WhenOptionsIsNotProvided_ExpectsRetrievedOptionsEmpty() 107 | { 108 | Regex r = new Regex(""regex""); 109 | var options = r.Options; 110 | } 111 | }", 112 | TestSettingsData.NUnitSettings 113 | }; 114 | 115 | // A test method targeting a method has its first part matching the name of the method under test. 116 | yield return new object[] 117 | { 118 | @"using NUnit.Framework; 119 | class RegexUnitTests 120 | { 121 | [Test] 122 | public void IsMatch_UsingNonMatchingString_ExpectsFalse() 123 | { 124 | Regex r = new Regex(""regex""); 125 | var result = r.IsMatch(""Foo""); 126 | } 127 | }", 128 | TestSettingsData.NoSettings 129 | }; 130 | 131 | // A test method name has its member under test part matching the name of the method under test. 132 | // The analyzer settings provides a new regex that defines a group named 'memberUnderTestName'. 133 | yield return new object[] 134 | { 135 | @"using NUnit.Framework; 136 | class RegexUnitTests 137 | { 138 | [Test] 139 | public void TestFoo_IsMatch() 140 | { 141 | Regex r = new Regex(""regex""); 142 | var result = r.IsMatch(""Foo""); 143 | } 144 | }", 145 | TestSettingsData.NUnitTestSettingsMemberUnderTestRegexFormat 146 | }; 147 | } 148 | 149 | IEnumerator IEnumerable.GetEnumerator() 150 | { 151 | return this.GetEnumerator(); 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/TestNameMustIncludeMemberUnderTestAnalyzerXunitTestInvalidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class TestNameMustIncludeMemberUnderTestAnalyzerXunitTestInvalidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // A test method targeting a constructor does not have its first part matching the name of the constructor under test. 11 | yield return new object[] 12 | { 13 | @"using Xunit; 14 | class RegexUnitTests 15 | { 16 | [Fact] 17 | public void TestCtor_UsingNullString_ThrowsArgumentNullException() 18 | { 19 | Regex r = new Regex(null); 20 | } 21 | }", 22 | "TestCtor_UsingNullString_ThrowsArgumentNullException", // Diagnostic message paramater 23 | "TestCtor", // Diagnostic message parameter 24 | 5, // Violation line 25 | 13, // Violation column. 26 | TestSettingsData.XunitSettings 27 | }; 28 | 29 | // A test method targeting a property does not have its first part matching the name of the property under test. 30 | yield return new object[] 31 | { 32 | @"using Xunit; 33 | class RegexUnitTests 34 | { 35 | [Theory] 36 | public void TestProperty_WhenOptionsIsNotProvided_ExpectsRetrievedOptionsEmpty() 37 | { 38 | Regex r = new Regex(""regex""); 39 | var options = r.Options; 40 | } 41 | }", 42 | "TestProperty_WhenOptionsIsNotProvided_ExpectsRetrievedOptionsEmpty", 43 | "TestProperty", 44 | 5, 45 | 13, 46 | TestSettingsData.XunitSettings 47 | }; 48 | 49 | // A test method targeting a method does not have its first part matching the name of the method under test. 50 | yield return new object[] 51 | { 52 | @"using Xunit; 53 | class RegexUnitTests 54 | { 55 | [Fact] 56 | public void TestMethod_UsingNonMatchingString_ExpectsFalse() 57 | { 58 | Regex r = new Regex(""regex""); 59 | var result = r.IsMatch(""Foo""); 60 | } 61 | }", 62 | "TestMethod_UsingNonMatchingString_ExpectsFalse", 63 | "TestMethod", 64 | 5, 65 | 13, 66 | TestSettingsData.XunitSettings 67 | }; 68 | 69 | // A test method targeting a method does not have its first part matching the name of the method under test. 70 | // Instead that part matches the name of a variable within the test body. 71 | yield return new object[] 72 | { 73 | @"using Xunit; 74 | class RegexUnitTests 75 | { 76 | [Theory] 77 | public void result_UsingNonMatchingString_ExpectsFalse() 78 | { 79 | Regex r = new Regex(""regex""); 80 | var result = r.IsMatch(""Foo""); 81 | } 82 | }", 83 | "result_UsingNonMatchingString_ExpectsFalse", 84 | "result", 85 | 5, 86 | 13, 87 | TestSettingsData.XunitSettings 88 | }; 89 | 90 | // A test method targeting a method does not have its first part matching the name of the method under test. 91 | // Instead that part matches the name of a parameter within the test body. 92 | yield return new object[] 93 | { 94 | @"using Xunit; 95 | class RegexUnitTests 96 | { 97 | [Theory] 98 | public void Foo_UsingNonMatchingString_ExpectsFalse() 99 | { 100 | Regex r = new Regex(""regex""); 101 | var result = r.IsMatch(""Foo""); 102 | } 103 | }", 104 | "Foo_UsingNonMatchingString_ExpectsFalse", 105 | "Foo", 106 | 5, 107 | 13, 108 | TestSettingsData.XunitSettings 109 | }; 110 | 111 | // A test method targeting a method does not have its first part matching the name of the method under test. 112 | // Instead that part matches a comment withing the method body. 113 | yield return new object[] 114 | { 115 | @"using Xunit; 116 | class RegexUnitTests 117 | { 118 | [Fact] 119 | public void Init_UsingNonMatchingString_ExpectsFalse() 120 | { 121 | // Init. 122 | Regex r = new Regex(""regex""); 123 | var result = r.IsMatch(""Foo""); 124 | } 125 | }", 126 | "Init_UsingNonMatchingString_ExpectsFalse", 127 | "Init", 128 | 5, 129 | 13, 130 | TestSettingsData.XunitSettings 131 | }; 132 | 133 | // A test method name not have its member under test part matching the name of the method under test. 134 | // The analyzer settings provides a new regex that defines a group named 'memberUnderTestName'. 135 | yield return new object[] 136 | { 137 | @"using Xunit; 138 | class RegexUnitTests 139 | { 140 | [Theory] 141 | public void TestFoo_Method() 142 | { 143 | Regex r = new Regex(""regex""); 144 | var result = r.IsMatch(""Foo""); 145 | } 146 | }", 147 | "TestFoo_Method", 148 | "Method", 149 | 5, 150 | 13, 151 | TestSettingsData.XunitTestSettingsMemberUnderTestRegexFormat 152 | }; 153 | } 154 | 155 | IEnumerator IEnumerable.GetEnumerator() 156 | { 157 | return this.GetEnumerator(); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/TestNameMustIncludeMemberUnderTestAnalyzerXunitTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class TestNameMustIncludeMemberUnderTestAnalyzerXunitTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // The test method name does not match the Regex pattern in the member under test group. 11 | yield return new object[] 12 | { 13 | @"using Xunit; 14 | class RegexUnitTests 15 | { 16 | [Fact] 17 | public void TestCtor!_UsingNullString_ThrowsArgumentNullException() 18 | { 19 | Regex r = new Regex(null); 20 | } 21 | }", 22 | TestSettingsData.XunitSettings 23 | }; 24 | 25 | // The test method with empty body. 26 | yield return new object[] 27 | { 28 | @"using Xunit; 29 | class RegexUnitTests 30 | { 31 | [Theory] 32 | public void TestMethod_UsingNullString_ThrowsArgumentNullException() 33 | { 34 | } 35 | }", 36 | TestSettingsData.XunitSettings 37 | }; 38 | 39 | // The test method with body containing comments only. 40 | yield return new object[] 41 | { 42 | @"using Xunit; 43 | class RegexUnitTests 44 | { 45 | [Fact] 46 | public void TestMethod_UsingNullString_ThrowsArgumentNullException() 47 | { 48 | // Comment. 49 | } 50 | }", 51 | TestSettingsData.XunitSettings 52 | }; 53 | 54 | // The test method with body containing a variable declaration only. 55 | yield return new object[] 56 | { 57 | @"using Xunit; 58 | class RegexUnitTests 59 | { 60 | [Theory] 61 | public void TestMethod_UsingNullString_ThrowsArgumentNullException() 62 | { 63 | string str = ""foo"" 64 | } 65 | }", 66 | TestSettingsData.XunitSettings 67 | }; 68 | 69 | // The test method name does not match the Regex pattern in another part of the name. 70 | yield return new object[] 71 | { 72 | @"using Xunit; 73 | class RegexUnitTests 74 | { 75 | [Fact] 76 | public void TestCtor_NullString_ThrowsArgumentNullException() 77 | { 78 | Regex r = new Regex(null); 79 | } 80 | }", 81 | TestSettingsData.XunitSettings 82 | }; 83 | 84 | // A test method targeting a constructor hase its first part matching the name of the constructor under test. 85 | yield return new object[] 86 | { 87 | @"using Xunit; 88 | class RegexUnitTests 89 | { 90 | [Fact] 91 | public void Regex_UsingNullString_ThrowsArgumentNullException() 92 | { 93 | Regex r = new Regex(null); 94 | } 95 | }", 96 | TestSettingsData.XunitSettings 97 | }; 98 | 99 | // A test method targeting a property has its first part matching the name of the property under test. 100 | yield return new object[] 101 | { 102 | @"using Xunit; 103 | class RegexUnitTests 104 | { 105 | [Theory] 106 | public void Options_WhenOptionsIsNotProvided_ExpectsRetrievedOptionsEmpty() 107 | { 108 | Regex r = new Regex(""regex""); 109 | var options = r.Options; 110 | } 111 | }", 112 | TestSettingsData.XunitSettings 113 | }; 114 | 115 | // A test method targeting a method has its first part matching the name of the method under test. 116 | yield return new object[] 117 | { 118 | @"using Xunit; 119 | class RegexUnitTests 120 | { 121 | [Fact] 122 | public void IsMatch_UsingNonMatchingString_ExpectsFalse() 123 | { 124 | Regex r = new Regex(""regex""); 125 | var result = r.IsMatch(""Foo""); 126 | } 127 | }", 128 | TestSettingsData.NoSettings 129 | }; 130 | 131 | // A test method name has its member under test part matching the name of the method under test. 132 | // The analyzer settings provides a new regex that defines a group named 'memberUnderTestName'. 133 | yield return new object[] 134 | { 135 | @"using Xunit; 136 | class RegexUnitTests 137 | { 138 | [Theory] 139 | public void TestFoo_IsMatch() 140 | { 141 | Regex r = new Regex(""regex""); 142 | var result = r.IsMatch(""Foo""); 143 | } 144 | }", 145 | TestSettingsData.XunitTestSettingsMemberUnderTestRegexFormat 146 | }; 147 | } 148 | 149 | IEnumerator IEnumerable.GetEnumerator() 150 | { 151 | return this.GetEnumerator(); 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/TestSettingsData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using Newtonsoft.Json; 4 | 5 | internal static class TestSettingsData 6 | { 7 | internal const string XunitSettings = @"{ 8 | ""settings"" : { 9 | ""unitTestFramework"" : ""Xunit"" 10 | } 11 | }"; 12 | 13 | internal const string NUnitSettings = @"{ 14 | ""settings"" : { 15 | ""unitTestFramework"" : ""NUnit"" 16 | } 17 | }"; 18 | 19 | internal const string InvalidSettings = @" 20 | ""settings"" : { 21 | ""unitTestFramework"" , ""MSTest"" 22 | } 23 | }"; 24 | 25 | internal const string MSTestSettings = @"{ 26 | ""settings"" : { 27 | ""unitTestFramework"" : ""MSTest"" 28 | } 29 | }"; 30 | 31 | private const string TestMethodNameFormatSimpleRegex = "\"\\\\b[a-zA-Z]{4,}\\\\b\""; 32 | private const string TestMethodNameSimpleFormatJson = "\"(a-zA-Z)[4...n]\""; 33 | private const string TestMethodNameMemberUnderTestRegex = "\"\\\\b[a-zA-Z]{4,}_(?[a-zA-Z]+)\\\\b\""; 34 | 35 | internal static string[] TestMethodNameFormatSimpleRegexExamples => new[] { "TestMethodOne", "TestMethodTwo" }; 36 | 37 | internal static string TestMethodNameSimpleFormat => TestMethodNameSimpleFormatJson.Trim('"'); 38 | 39 | internal static string MSTestSettingsSimpleRegex => 40 | $@"{{ 41 | ""settings"" : {{ 42 | ""unitTestFramework"" : ""MSTest"", 43 | ""testMethodNameFormat"" : {TestMethodNameSimpleFormatJson}, 44 | ""testMethodNameFormatRegex"" : {{""Pattern"" : {TestMethodNameFormatSimpleRegex} }}, 45 | ""testMethodNameFormatExamples"" : {JsonConvert.SerializeObject(TestMethodNameFormatSimpleRegexExamples)} 46 | }} 47 | }}"; 48 | 49 | internal static string XunitTestSettingsSimpleRegex => 50 | $@"{{ 51 | ""settings"" : {{ 52 | ""unitTestFramework"" : ""Xunit"", 53 | ""testMethodNameFormat"" : {TestMethodNameSimpleFormatJson}, 54 | ""testMethodNameFormatRegex"" : {{""Pattern"" : {TestMethodNameFormatSimpleRegex} }}, 55 | ""testMethodNameFormatExamples"" : {JsonConvert.SerializeObject(TestMethodNameFormatSimpleRegexExamples)} 56 | }} 57 | }}"; 58 | 59 | internal static string NUnitTestSettingsSimpleRegex => 60 | $@"{{ 61 | ""settings"" : {{ 62 | ""unitTestFramework"" : ""NUnit"", 63 | ""testMethodNameFormat"" : {TestMethodNameSimpleFormatJson}, 64 | ""testMethodNameFormatRegex"" : {{""Pattern"" : {TestMethodNameFormatSimpleRegex} }}, 65 | ""testMethodNameFormatExamples"" : {JsonConvert.SerializeObject(TestMethodNameFormatSimpleRegexExamples)} 66 | }} 67 | }}"; 68 | 69 | internal static string XunitTestSettingsSimpleRegexNoFormat => 70 | $@"{{ 71 | ""settings"" : {{ 72 | ""unitTestFramework"" : ""Xunit"", 73 | ""testMethodNameFormatRegex"" : {{""Pattern"" : {TestMethodNameFormatSimpleRegex} }}, 74 | ""testMethodNameFormatExamples"" : {JsonConvert.SerializeObject(TestMethodNameFormatSimpleRegexExamples)} 75 | }} 76 | }}"; 77 | 78 | internal static string NUnitTestSettingsSimpleRegexNoFormat => 79 | $@"{{ 80 | ""settings"" : {{ 81 | ""unitTestFramework"" : ""NUnit"", 82 | ""testMethodNameFormatRegex"" : {{""Pattern"" : {TestMethodNameFormatSimpleRegex} }}, 83 | ""testMethodNameFormatExamples"" : {JsonConvert.SerializeObject(TestMethodNameFormatSimpleRegexExamples)} 84 | }} 85 | }}"; 86 | 87 | internal static string MSTestSettingsSimpleRegexNoFormat => 88 | $@"{{ 89 | ""settings"" : {{ 90 | ""unitTestFramework"" : ""MSTest"", 91 | ""testMethodNameFormatRegex"" : {{""Pattern"" : {TestMethodNameFormatSimpleRegex} }}, 92 | ""testMethodNameFormatExamples"" : {JsonConvert.SerializeObject(TestMethodNameFormatSimpleRegexExamples)} 93 | }} 94 | }}"; 95 | 96 | internal static string MSTestSettingsSimpleRegexNoSampleProvided => 97 | $@"{{ 98 | ""settings"" : {{ 99 | ""unitTestFramework"" : ""MSTest"", 100 | ""testMethodNameFormat"" : {TestMethodNameSimpleFormatJson}, 101 | ""testMethodNameFormatRegex"" : {{""Pattern"" : {TestMethodNameFormatSimpleRegex} }}, 102 | }} 103 | }}"; 104 | 105 | internal static string XunitTestSettingsMemberUnderTestRegexFormat => 106 | $@"{{ 107 | ""settings"" : {{ 108 | ""unitTestFramework"" : ""Xunit"", 109 | ""testMethodNameFormatRegex"" : {{""Pattern"" : {TestMethodNameMemberUnderTestRegex} }} 110 | }} 111 | }}"; 112 | 113 | internal static string NUnitTestSettingsMemberUnderTestRegexFormat => 114 | $@"{{ 115 | ""settings"" : {{ 116 | ""unitTestFramework"" : ""NUnit"", 117 | ""testMethodNameFormatRegex"" : {{""Pattern"" : {TestMethodNameMemberUnderTestRegex} }} 118 | }} 119 | }}"; 120 | 121 | internal static string MSTestSettingsMemberUnderTestRegexFormat => 122 | $@"{{ 123 | ""settings"" : {{ 124 | ""unitTestFramework"" : ""MSTest"", 125 | ""testMethodNameFormatRegex"" : {{""Pattern"" : {TestMethodNameMemberUnderTestRegex} }} 126 | }} 127 | }}"; 128 | 129 | internal static string NoSettings => string.Empty; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseAAACommentsAnalyzerMSTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseAAACommentsAnalyzerMSTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // A test method with empty body. 11 | yield return new object[] 12 | { 13 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 14 | class RegexUnitTests 15 | { 16 | [TestMethod] 17 | public void Regex_UsingNullString_ThrowsArgumentNullException() 18 | { 19 | } 20 | }", 21 | TestSettingsData.NoSettings 22 | }; 23 | 24 | // A test method that does not invoke a member or constructor. 25 | yield return new object[] 26 | { 27 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 28 | class RegexUnitTests 29 | { 30 | [TestMethod] 31 | public void Regex_UsingNullString_ThrowsArgumentNullException() 32 | { 33 | string foo = ""foo""; 34 | } 35 | }", 36 | TestSettingsData.NoSettings 37 | }; 38 | 39 | // A test method with the // Arrange. // Act. // Assert. comments. 40 | // Each AAA comment appears only once and in the expected order. 41 | // The first line of the test body is // Arrange. 42 | yield return new object[] 43 | { 44 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 45 | class RegexUnitTests 46 | { 47 | [TestMethod] 48 | public void Split_UsingSplitableString_ExpectsStringIsSplit() 49 | { 50 | // Arrange. 51 | string foo = ""foo foo""; 52 | 53 | // Act. 54 | var parts = foo.Split(' ')[0]; 55 | 56 | // Assert. 57 | Assert.IsNotNull(parts); 58 | } 59 | }", 60 | TestSettingsData.NoSettings 61 | }; 62 | } 63 | 64 | IEnumerator IEnumerable.GetEnumerator() 65 | { 66 | return this.GetEnumerator(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseAAACommentsAnalyzerNUnitTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseAAACommentsAnalyzerNUnitTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // A test method with empty body. 11 | yield return new object[] 12 | { 13 | @"using NUnit.Framework; 14 | class RegexUnitTests 15 | { 16 | [Test] 17 | public void Regex_UsingNullString_ThrowsArgumentNullException() 18 | { 19 | } 20 | }", 21 | TestSettingsData.NUnitSettings 22 | }; 23 | 24 | // A test method that does not invoke a member or constructor. 25 | yield return new object[] 26 | { 27 | @"using NUnit.Framework; 28 | class RegexUnitTests 29 | { 30 | [Test] 31 | public void Regex_UsingNullString_ThrowsArgumentNullException() 32 | { 33 | string foo = ""foo""; 34 | } 35 | }", 36 | TestSettingsData.NUnitSettings 37 | }; 38 | 39 | // A test method with the // Arrange. // Act. // Assert. comments. 40 | // Each AAA comment appears only once and in the expected order. 41 | // The first line of the test body is // Arrange. 42 | yield return new object[] 43 | { 44 | @"using NUnit.Framework; 45 | class RegexUnitTests 46 | { 47 | [Test] 48 | public void Split_UsingSplitableString_ExpectsStringIsSplit() 49 | { 50 | // Arrange. 51 | string foo = ""foo foo""; 52 | 53 | // Act. 54 | var parts = foo.Split(' ')[0]; 55 | 56 | // Assert. 57 | Assert.IsNotNull(parts); 58 | } 59 | }", 60 | TestSettingsData.NUnitSettings 61 | }; 62 | } 63 | 64 | IEnumerator IEnumerable.GetEnumerator() 65 | { 66 | return this.GetEnumerator(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseAAACommentsAnalyzerXunitTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseAAACommentsAnalyzerXunitTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // A test method with empty body. 11 | yield return new object[] 12 | { 13 | @"using Xunit; 14 | class RegexUnitTests 15 | { 16 | [Theory] 17 | public void Regex_UsingNullString_ThrowsArgumentNullException() 18 | { 19 | } 20 | }", 21 | TestSettingsData.XunitSettings 22 | }; 23 | 24 | // A test method that does not invoke a member or constructor. 25 | yield return new object[] 26 | { 27 | @"using Xunit; 28 | class RegexUnitTests 29 | { 30 | [Fact] 31 | public void Regex_UsingNullString_ThrowsArgumentNullException() 32 | { 33 | string foo = ""foo""; 34 | } 35 | }", 36 | TestSettingsData.XunitSettings 37 | }; 38 | 39 | // A test method with the // Arrange. // Act. // Assert. comments. 40 | // Each AAA comment appears only once and in the expected order. 41 | // The first line of the test body is // Arrange. 42 | yield return new object[] 43 | { 44 | @"using Xunit; 45 | class RegexUnitTests 46 | { 47 | [Theory] 48 | public void Split_UsingSplitableString_ExpectsStringIsSplit() 49 | { 50 | // Arrange. 51 | string foo = ""foo foo""; 52 | 53 | // Act. 54 | var parts = foo.Split(' ')[0]; 55 | 56 | // Assert. 57 | Assert.IsNotNull(parts); 58 | } 59 | }", 60 | TestSettingsData.XunitSettings 61 | }; 62 | } 63 | 64 | IEnumerator IEnumerable.GetEnumerator() 65 | { 66 | return this.GetEnumerator(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseCorrectTestNameFormatMSTestInvalidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using Settings.ObjectModel; 6 | 7 | internal class UseCorrectTestNameFormatMSTestInvalidData : IEnumerable 8 | { 9 | public IEnumerator GetEnumerator() 10 | { 11 | // A MSTest TestMethod attribute is present (using statement) and the method name does not have the expected format. 12 | yield return new object[] 13 | { 14 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 15 | class ClassName 16 | { 17 | [TestMethod] 18 | public void Test1() {} 19 | }", 20 | "Test1", // Diagnostic message paramater 21 | 5, // Violation line 22 | 13, // Violation column. 23 | TestSettingsData.MSTestSettingsSimpleRegex, 24 | TestSettingsData.TestMethodNameSimpleFormat, 25 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 26 | }; 27 | 28 | // A MSTest TestMethod attribute is present (fully qualified name) and the method name does not have the expected format. 29 | yield return new object[] 30 | { 31 | @" 32 | class ClassNameTests 33 | { 34 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod] 35 | public void Test1() {} 36 | }", 37 | "Test1", 38 | 5, 39 | 13, 40 | TestSettingsData.MSTestSettingsSimpleRegex, 41 | TestSettingsData.TestMethodNameSimpleFormat, 42 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 43 | }; 44 | 45 | // A MSTest TestMethod attribute is grouped along with another attribute and the method name does not have the expected format. 46 | yield return new object[] 47 | { 48 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 49 | class ClassNameTests 50 | { 51 | [MyAttribute, TestMethod] 52 | public void Test1() {} 53 | }", 54 | "Test1", 55 | 5, 56 | 13, 57 | TestSettingsData.MSTestSettingsSimpleRegex, 58 | TestSettingsData.TestMethodNameSimpleFormat, 59 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 60 | }; 61 | 62 | // A MSTest TestMethod attribute is present along with another attribute and the method name does not have the expected format. 63 | yield return new object[] 64 | { 65 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 66 | class ClassNameTests 67 | { 68 | [MyAttribute] 69 | [TestMethod] 70 | public void Test1() {} 71 | }", 72 | "Test1", 73 | 6, 74 | 13, 75 | TestSettingsData.MSTestSettingsSimpleRegex, 76 | TestSettingsData.TestMethodNameSimpleFormat, 77 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 78 | }; 79 | 80 | // A MSTest TestMethod is present and the method name does not have the expected format. 81 | // A configuration settings is not provided therefore the default settings should be used. 82 | yield return new object[] 83 | { 84 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 85 | class ClassName 86 | { 87 | [TestMethod] 88 | public void TestOne() {} 89 | }", 90 | "TestOne", 91 | 5, 92 | 13, 93 | TestSettingsData.NoSettings, 94 | AnalyzersSettings.DefaultFormat, 95 | AnalyzersSettings.TestMethodNameFormatDefaultRegexExamples 96 | }; 97 | 98 | // A MSTest TestMethod is present and the method name does not have the expected format. 99 | // A configuration settings is provided without a regex therefore the default regex should be used. 100 | yield return new object[] 101 | { 102 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 103 | class ClassName 104 | { 105 | [TestMethod] 106 | public void TestOne() {} 107 | }", 108 | "TestOne", 109 | 5, 110 | 13, 111 | TestSettingsData.MSTestSettings, 112 | AnalyzersSettings.DefaultFormat, 113 | AnalyzersSettings.TestMethodNameFormatDefaultRegexExamples 114 | }; 115 | 116 | // A MSTest TestMethod is present and the method name does not have the expected format. 117 | // An invalid configuration settings is provided therefore the default settings should be used. 118 | yield return new object[] 119 | { 120 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 121 | class ClassName 122 | { 123 | [TestMethod] 124 | public void TestOne() {} 125 | }", 126 | "TestOne", 127 | 5, 128 | 13, 129 | TestSettingsData.InvalidSettings, 130 | AnalyzersSettings.DefaultFormat, 131 | AnalyzersSettings.TestMethodNameFormatDefaultRegexExamples 132 | }; 133 | 134 | // A MSTest TestMethod is present and the method name does not have the expected format. 135 | // No format is provided as part of the settings therefore the default format should be used in the message. 136 | yield return new object[] 137 | { 138 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 139 | class ClassName 140 | { 141 | [TestMethod] 142 | public void Test1() {} 143 | }", 144 | "Test1", 145 | 5, 146 | 13, 147 | TestSettingsData.MSTestSettingsSimpleRegexNoFormat, 148 | AnalyzersSettings.DefaultFormat, 149 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 150 | }; 151 | 152 | // A MSTest TestMethod is present and the method name does not have the expected format. 153 | // No examples are provided as part of the settings therefore the default example should be found in the message. 154 | yield return new object[] 155 | { 156 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 157 | class ClassName 158 | { 159 | [TestMethod] 160 | public void Test1() {} 161 | }", 162 | "Test1", 163 | 5, 164 | 13, 165 | TestSettingsData.MSTestSettingsSimpleRegexNoSampleProvided, 166 | TestSettingsData.TestMethodNameSimpleFormat, 167 | new[] { AnalyzersSettings.NoTestMethodNameExamplesProvided } 168 | }; 169 | } 170 | 171 | IEnumerator IEnumerable.GetEnumerator() 172 | { 173 | return this.GetEnumerator(); 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseCorrectTestNameFormatMSTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseCorrectTestNameFormatMSTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // No method attribute is present. 11 | yield return new object[] 12 | { 13 | @" 14 | class ClassName 15 | { 16 | public void Test1() {} 17 | }", 18 | TestSettingsData.NoSettings 19 | }; 20 | 21 | // A random method attribute is present. 22 | yield return new object[] 23 | { 24 | @" 25 | class ClassName 26 | { 27 | [MyAttribute] 28 | public void Test1() {} 29 | }", 30 | TestSettingsData.NoSettings 31 | }; 32 | 33 | // A non-MSTest TestMethod attribute is present (fully qualified name). 34 | yield return new object[] 35 | { 36 | @" 37 | class ClassName 38 | { 39 | [UnitTestAnalyzers.Test.Attributes.TestMethod] 40 | public void Test1() {} 41 | }", 42 | TestSettingsData.NoSettings 43 | }; 44 | 45 | // A non-MSTest TestMethod attribute is present (using statement). 46 | yield return new object[] 47 | { 48 | @"using UnitTestAnalyzers.Test.Attributes; 49 | class ClassNameTests 50 | { 51 | [TestMethod] 52 | public void Test1() {} 53 | }", 54 | TestSettingsData.NoSettings 55 | }; 56 | 57 | // A MSTest TestMethod attribute is present (using statement) and the method name has the expected format. 58 | yield return new object[] 59 | { 60 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 61 | class ClassName 62 | { 63 | [TestMethod] 64 | public void TestOne_WhenFoo_ExpectsResult() {} 65 | }", 66 | TestSettingsData.NoSettings 67 | }; 68 | 69 | // A MSTest TestMethod attribute is present (fully qualified named) and the method name has the expected format. 70 | yield return new object[] 71 | { 72 | @" 73 | class ClassName 74 | { 75 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod] 76 | public void TestOne_WhenFoo_ExpectsResult() {} 77 | }", 78 | TestSettingsData.NoSettings 79 | }; 80 | 81 | // A MSTest TestMethod attribute is present (using statement) and the method name has the expected format. 82 | // Additionally a settings file is provided that does not redefine the test method name regex. 83 | yield return new object[] 84 | { 85 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 86 | class ClassName 87 | { 88 | [TestMethod] 89 | public void TestOne_WhenFoo_ExpectsResult() {} 90 | }", 91 | TestSettingsData.MSTestSettings 92 | }; 93 | 94 | // A MSTest TestMethod attribute is present (using statement) and the method name has the expected format. 95 | // Additionally an invalid test settings is provided, therefore the default settings should be used. 96 | yield return new object[] 97 | { 98 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 99 | class ClassName 100 | { 101 | [TestMethod] 102 | public void TestOne_WhenFoo_ExpectsResult() {} 103 | }", 104 | TestSettingsData.InvalidSettings 105 | }; 106 | 107 | // A MSTest TestMethod attribute is present (using statement) and the method name has the expected format. 108 | // Additionally a settings is provided redefining the test name regex. 109 | yield return new object[] 110 | { 111 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 112 | class ClassName 113 | { 114 | [TestMethod] 115 | public void TestOne() {} 116 | }", 117 | TestSettingsData.MSTestSettingsSimpleRegex 118 | }; 119 | } 120 | 121 | IEnumerator IEnumerable.GetEnumerator() 122 | { 123 | return this.GetEnumerator(); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseCorrectTestNameFormatNUnitTestInvalidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using Settings.ObjectModel; 6 | 7 | internal class UseCorrectTestNameFormatNUnitTestInvalidData : IEnumerable 8 | { 9 | public IEnumerator GetEnumerator() 10 | { 11 | // A NUnit Test attribute is present (using statement) and the method name does not have the expected format. 12 | yield return new object[] 13 | { 14 | @"using NUnit.Framework; 15 | class ClassName 16 | { 17 | [Test] 18 | public void Test1() {} 19 | }", 20 | "Test1", // Diagnostic message paramater 21 | 5, // Violation line 22 | 13, // Violation column. 23 | TestSettingsData.NUnitTestSettingsSimpleRegex, 24 | TestSettingsData.TestMethodNameSimpleFormat, 25 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 26 | }; 27 | 28 | // A NUnit TestCase attribute is present (using statement) and the method name does not have the expected format. 29 | yield return new object[] 30 | { 31 | @"using NUnit.Framework; 32 | class ClassName 33 | { 34 | [TestCase] 35 | public void Test1() {} 36 | }", 37 | "Test1", 38 | 5, 39 | 13, 40 | TestSettingsData.NUnitTestSettingsSimpleRegex, 41 | TestSettingsData.TestMethodNameSimpleFormat, 42 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 43 | }; 44 | 45 | // A NUnit Test attribute is present (fully qualified name) and the method name does not have the expected format. 46 | yield return new object[] 47 | { 48 | @" 49 | class ClassName 50 | { 51 | [NUnit.Framework.Test] 52 | public void Test1() {} 53 | }", 54 | "Test1", 55 | 5, 56 | 13, 57 | TestSettingsData.NUnitTestSettingsSimpleRegex, 58 | TestSettingsData.TestMethodNameSimpleFormat, 59 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 60 | }; 61 | 62 | // A NUnit.Framework TestCase attribute is present (fully qualified name) and the method name does not have the expected format. 63 | yield return new object[] 64 | { 65 | @" 66 | class ClassName 67 | { 68 | [NUnit.Framework.TestCase] 69 | public void Test1() {} 70 | }", 71 | "Test1", 72 | 5, 73 | 13, 74 | TestSettingsData.NUnitTestSettingsSimpleRegex, 75 | TestSettingsData.TestMethodNameSimpleFormat, 76 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 77 | }; 78 | 79 | // A NUNit Test attribute is grouped along with another attribute and the method name does not have the expected format. 80 | yield return new object[] 81 | { 82 | @"using NUnit.Framework; 83 | class ClassNameTests 84 | { 85 | [MyAttribute, Test] 86 | public void Test1() {} 87 | }", 88 | "Test1", 89 | 5, 90 | 13, 91 | TestSettingsData.NUnitTestSettingsSimpleRegex, 92 | TestSettingsData.TestMethodNameSimpleFormat, 93 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 94 | }; 95 | 96 | // A NUnit TestCase attribute is grouped along with another attribute and the method name does not have the expected format. 97 | yield return new object[] 98 | { 99 | @"using NUnit.Framework; 100 | class ClassNameTests 101 | { 102 | [MyAttribute, TestCase] 103 | public void Test1() {} 104 | }", 105 | "Test1", 106 | 5, 107 | 13, 108 | TestSettingsData.NUnitTestSettingsSimpleRegex, 109 | TestSettingsData.TestMethodNameSimpleFormat, 110 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 111 | }; 112 | 113 | // A NUnit Test attribute is present along with another attribute and the method name does not have the expected format. 114 | yield return new object[] 115 | { 116 | @"using NUnit.Framework; 117 | class ClassNameTests 118 | { 119 | [MyAttribute] 120 | [Test] 121 | public void Test1() {} 122 | }", 123 | "Test1", 124 | 6, 125 | 13, 126 | TestSettingsData.NUnitTestSettingsSimpleRegex, 127 | TestSettingsData.TestMethodNameSimpleFormat, 128 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 129 | }; 130 | 131 | // A NUNit TestCase attribute is present along with another attribute and the method name does not have the expected format. 132 | yield return new object[] 133 | { 134 | @"using NUnit.Framework; 135 | class ClassNameTests 136 | { 137 | [MyAttribute] 138 | [TestCase] 139 | public void Test1() {} 140 | }", 141 | "Test1", 142 | 6, 143 | 13, 144 | TestSettingsData.NUnitTestSettingsSimpleRegex, 145 | TestSettingsData.TestMethodNameSimpleFormat, 146 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 147 | }; 148 | 149 | // A NUnit Test attribute is present and the method name does not have the expected format. 150 | // A configuration settings is provided without a regex therefore the default regex should be used. 151 | yield return new object[] 152 | { 153 | @"using NUnit.Framework; 154 | class ClassName 155 | { 156 | [Test] 157 | public void TestOne() {} 158 | }", 159 | "TestOne", 160 | 5, 161 | 13, 162 | TestSettingsData.NUnitSettings, 163 | AnalyzersSettings.DefaultFormat, 164 | AnalyzersSettings.TestMethodNameFormatDefaultRegexExamples 165 | }; 166 | 167 | // A NUnit TestCase attribute is present and the method name does not have the expected format. 168 | // A configuration settings is provided without a regex therefore the default regex should be used. 169 | yield return new object[] 170 | { 171 | @"using NUnit.Framework; 172 | class ClassName 173 | { 174 | [TestCase] 175 | public void TestOne() {} 176 | }", 177 | "TestOne", 178 | 5, 179 | 13, 180 | TestSettingsData.NUnitSettings, 181 | AnalyzersSettings.DefaultFormat, 182 | AnalyzersSettings.TestMethodNameFormatDefaultRegexExamples 183 | }; 184 | 185 | // A NUnit TestCase attribute is present and the method name does not have the expected format. 186 | // A configuration settings is provided without format therefore the default format should be found in the message. 187 | yield return new object[] 188 | { 189 | @"using NUnit.Framework; 190 | class ClassName 191 | { 192 | [TestCase] 193 | public void Test1() {} 194 | }", 195 | "Test1", 196 | 5, 197 | 13, 198 | TestSettingsData.NUnitTestSettingsSimpleRegexNoFormat, 199 | AnalyzersSettings.DefaultFormat, 200 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 201 | }; 202 | } 203 | 204 | IEnumerator IEnumerable.GetEnumerator() 205 | { 206 | return this.GetEnumerator(); 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseCorrectTestNameFormatNUnitTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseCorrectTestNameFormatNUnitTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // No method attribute is present. 11 | yield return new object[] 12 | { 13 | @" 14 | class ClassName 15 | { 16 | public void Test1() {} 17 | }", 18 | TestSettingsData.NUnitTestSettingsSimpleRegex 19 | }; 20 | 21 | // A random method attribute is present. 22 | yield return new object[] 23 | { 24 | @" 25 | class ClassName 26 | { 27 | [MyAttribute] 28 | public void Test1() {} 29 | }", 30 | TestSettingsData.NUnitTestSettingsSimpleRegex 31 | }; 32 | 33 | // A NUnit Test attribute is present (fully qualified name). 34 | yield return new object[] 35 | { 36 | @" 37 | class ClassName 38 | { 39 | [UnitTestAnalyzers.Test.Attributes.Test] 40 | public void Test1() {} 41 | }", 42 | TestSettingsData.NUnitTestSettingsSimpleRegex 43 | }; 44 | 45 | // A non-NUnit TestCase attribute is present (fully qualified name). 46 | yield return new object[] 47 | { 48 | @" 49 | class ClassName 50 | { 51 | [UnitTestAnalyzers.Test.Attributes.TestCase] 52 | public void Test1() {} 53 | }", 54 | TestSettingsData.NUnitTestSettingsSimpleRegex 55 | }; 56 | 57 | // A non-NUnit Test attribute is present (using statement). 58 | yield return new object[] 59 | { 60 | @"using UnitTestAnalyzers.Test.Attributes; 61 | class ClassNameTests 62 | { 63 | [Test] 64 | public void Test1() {} 65 | }", 66 | TestSettingsData.NUnitTestSettingsSimpleRegex 67 | }; 68 | 69 | // A non-NUnit TestCase attribute is present (using statement). 70 | yield return new object[] 71 | { 72 | @"using UnitTestAnalyzers.Test.Attributes; 73 | class ClassNameTests 74 | { 75 | [TestCase] 76 | public void Test1() {} 77 | }", 78 | TestSettingsData.NUnitTestSettingsSimpleRegex 79 | }; 80 | 81 | // A NUnit Test attribute is present (using statement) and the method name has the expected format. 82 | // The provided settings does not contain a regex therefore the default format is enforced. 83 | yield return new object[] 84 | { 85 | @"using NUnit.Framework; 86 | class ClassName 87 | { 88 | [Test] 89 | public void TestOne_UsingFoo_ThrowsResult() {} 90 | }", 91 | TestSettingsData.NUnitSettings 92 | }; 93 | 94 | // A NUnit TestCase attribute is present (using statement) and the method name has the expected format. 95 | // The provided settings does not contain a regex therefore the default format is enforced. 96 | yield return new object[] 97 | { 98 | @"using NUnit.Framework; 99 | class ClassName 100 | { 101 | [TestCase] 102 | public void TestOne_UsingFoo_ThrowsResult() {} 103 | }", 104 | TestSettingsData.NUnitSettings 105 | }; 106 | 107 | // A NUnit Test attribute is present (fully qualified named) and the method name has the expected format. 108 | // The provided settings does not contain a regex therefore the default format is enforced. 109 | yield return new object[] 110 | { 111 | @" 112 | class ClassName 113 | { 114 | [NUnit.Framework.Test] 115 | public void TestOne_WhenFoo_ExpectsResult() {} 116 | }", 117 | TestSettingsData.NUnitSettings 118 | }; 119 | 120 | // A NUnit TestCase attribute is present (fully qualified named) and the method name has the expected format. 121 | // The provided settings does not contain a regex therefore the default format is enforced.p 122 | yield return new object[] 123 | { 124 | @" 125 | class ClassName 126 | { 127 | [NUnit.Framework.TestCase] 128 | public void TestOne_WhenFoo_ExpectsResult() {} 129 | }", 130 | TestSettingsData.NUnitSettings 131 | }; 132 | 133 | // A NUnit Test attribute is present (using statement) and the method name has the expected format. 134 | // Additionally a settings is provided redefining the test name regex. 135 | yield return new object[] 136 | { 137 | @"using NUnit.Framework; 138 | class ClassName 139 | { 140 | [Test] 141 | public void TestOne() {} 142 | }", 143 | TestSettingsData.NUnitTestSettingsSimpleRegex 144 | }; 145 | 146 | // A NUnit TestCase attribute is present (using statement) and the method name has the expected format. 147 | // Additionally a settings is provided redefining the test name regex. 148 | yield return new object[] 149 | { 150 | @"using using NUnit.Framework; 151 | class ClassName 152 | { 153 | [TestCase] 154 | public void TestOne() {} 155 | }", 156 | TestSettingsData.NUnitTestSettingsSimpleRegex 157 | }; 158 | } 159 | 160 | IEnumerator IEnumerable.GetEnumerator() 161 | { 162 | return this.GetEnumerator(); 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseCorrectTestNameFormatXunitTestInvalidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using Settings.ObjectModel; 6 | 7 | internal class UseCorrectTestNameFormatXunitTestInvalidData : IEnumerable 8 | { 9 | public IEnumerator GetEnumerator() 10 | { 11 | // A Xunit Fact attribute is present (using statement) and the method name does not have the expected format. 12 | yield return new object[] 13 | { 14 | @"using Xunit; 15 | class ClassName 16 | { 17 | [Fact] 18 | public void Test1() {} 19 | }", 20 | "Test1", // Diagnostic message paramater 21 | 5, // Violation line 22 | 13, // Violation column. 23 | TestSettingsData.XunitTestSettingsSimpleRegex, 24 | TestSettingsData.TestMethodNameSimpleFormat, 25 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 26 | }; 27 | 28 | // A Xunit Theory attribute is present (using statement) and the method name does not have the expected format. 29 | yield return new object[] 30 | { 31 | @"using Xunit; 32 | class ClassName 33 | { 34 | [Theory] 35 | public void Test1() {} 36 | }", 37 | "Test1", 38 | 5, 39 | 13, 40 | TestSettingsData.XunitTestSettingsSimpleRegex, 41 | TestSettingsData.TestMethodNameSimpleFormat, 42 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 43 | }; 44 | 45 | // A Xunit Fact attribute is present (fully qualified name) and the method name does not have the expected format. 46 | yield return new object[] 47 | { 48 | @" 49 | class ClassName 50 | { 51 | [Xunit.Fact] 52 | public void Test1() {} 53 | }", 54 | "Test1", 55 | 5, 56 | 13, 57 | TestSettingsData.XunitTestSettingsSimpleRegex, 58 | TestSettingsData.TestMethodNameSimpleFormat, 59 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 60 | }; 61 | 62 | // A Xunit Theory attribute is present (fully qualified name) and the method name does not have the expected format. 63 | yield return new object[] 64 | { 65 | @" 66 | class ClassName 67 | { 68 | [Xunit.Theory] 69 | public void Test1() {} 70 | }", 71 | "Test1", 72 | 5, 73 | 13, 74 | TestSettingsData.XunitTestSettingsSimpleRegex, 75 | TestSettingsData.TestMethodNameSimpleFormat, 76 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 77 | }; 78 | 79 | // A Xunit Fact attribute is grouped along with another attribute and the method name does not have the expected format. 80 | yield return new object[] 81 | { 82 | @"using Xunit; 83 | class ClassNameTests 84 | { 85 | [MyAttribute, Fact] 86 | public void Test1() {} 87 | }", 88 | "Test1", 89 | 5, 90 | 13, 91 | TestSettingsData.XunitTestSettingsSimpleRegex, 92 | TestSettingsData.TestMethodNameSimpleFormat, 93 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 94 | }; 95 | 96 | // A Xunit Theory attribute is grouped along with another attribute and the method name does not have the expected format. 97 | yield return new object[] 98 | { 99 | @"using Xunit; 100 | class ClassNameTests 101 | { 102 | [MyAttribute, Theory] 103 | public void Test1() {} 104 | }", 105 | "Test1", 106 | 5, 107 | 13, 108 | TestSettingsData.XunitTestSettingsSimpleRegex, 109 | TestSettingsData.TestMethodNameSimpleFormat, 110 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 111 | }; 112 | 113 | // A Xunit Fact attribute is present along with another attribute and the method name does not have the expected format. 114 | yield return new object[] 115 | { 116 | @"using Xunit; 117 | class ClassNameTests 118 | { 119 | [MyAttribute] 120 | [Fact] 121 | public void Test1() {} 122 | }", 123 | "Test1", 124 | 6, 125 | 13, 126 | TestSettingsData.XunitTestSettingsSimpleRegex, 127 | TestSettingsData.TestMethodNameSimpleFormat, 128 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 129 | }; 130 | 131 | // A Xunit Theory attribute is present along with another attribute and the method name does not have the expected format. 132 | yield return new object[] 133 | { 134 | @"using Xunit; 135 | class ClassNameTests 136 | { 137 | [MyAttribute] 138 | [Theory] 139 | public void Test1() {} 140 | }", 141 | "Test1", 142 | 6, 143 | 13, 144 | TestSettingsData.XunitTestSettingsSimpleRegex, 145 | TestSettingsData.TestMethodNameSimpleFormat, 146 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 147 | }; 148 | 149 | // A Xunit Fact attribute is present and the method name does not have the expected format. 150 | // A configuration settings is provided without a regex therefore the default regex should be used. 151 | yield return new object[] 152 | { 153 | @"using Xunit; 154 | class ClassName 155 | { 156 | [Fact] 157 | public void TestOne() {} 158 | }", 159 | "TestOne", 160 | 5, 161 | 13, 162 | TestSettingsData.XunitSettings, 163 | AnalyzersSettings.DefaultFormat, 164 | AnalyzersSettings.TestMethodNameFormatDefaultRegexExamples 165 | }; 166 | 167 | // A Xunit Theory attribute is present and the method name does not have the expected format. 168 | // A configuration settings is provided without a regex therefore the default regex should be used. 169 | yield return new object[] 170 | { 171 | @"using Xunit; 172 | class ClassName 173 | { 174 | [Theory] 175 | public void TestOne() {} 176 | }", 177 | "TestOne", 178 | 5, 179 | 13, 180 | TestSettingsData.XunitSettings, 181 | AnalyzersSettings.DefaultFormat, 182 | AnalyzersSettings.TestMethodNameFormatDefaultRegexExamples 183 | }; 184 | 185 | // A Xunit Theory attribute is present and the method name does not have the expected format. 186 | // A configuration settings is provided without format therefore the default format should be found in the message. 187 | yield return new object[] 188 | { 189 | @"using Xunit; 190 | class ClassName 191 | { 192 | [Theory] 193 | public void Test1() {} 194 | }", 195 | "Test1", 196 | 5, 197 | 13, 198 | TestSettingsData.XunitTestSettingsSimpleRegexNoFormat, 199 | AnalyzersSettings.DefaultFormat, 200 | TestSettingsData.TestMethodNameFormatSimpleRegexExamples 201 | }; 202 | } 203 | 204 | IEnumerator IEnumerable.GetEnumerator() 205 | { 206 | return this.GetEnumerator(); 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseCorrectTestNameFormatXunitTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseCorrectTestNameFormatXunitTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // No method attribute is present. 11 | yield return new object[] 12 | { 13 | @" 14 | class ClassName 15 | { 16 | public void Test1() {} 17 | }", 18 | TestSettingsData.XunitTestSettingsSimpleRegex 19 | }; 20 | 21 | // A random method attribute is present. 22 | yield return new object[] 23 | { 24 | @" 25 | class ClassName 26 | { 27 | [MyAttribute] 28 | public void Test1() {} 29 | }", 30 | TestSettingsData.XunitTestSettingsSimpleRegex 31 | }; 32 | 33 | // A non-Xunit Fact attribute is present (fully qualified name). 34 | yield return new object[] 35 | { 36 | @" 37 | class ClassName 38 | { 39 | [UnitTestAnalyzers.Test.Attributes.Fact] 40 | public void Test1() {} 41 | }", 42 | TestSettingsData.XunitTestSettingsSimpleRegex 43 | }; 44 | 45 | // A non-Xunit Theory attribute is present (fully qualified name). 46 | yield return new object[] 47 | { 48 | @" 49 | class ClassName 50 | { 51 | [UnitTestAnalyzers.Test.Attributes.Theory] 52 | public void Test1() {} 53 | }", 54 | TestSettingsData.XunitTestSettingsSimpleRegex 55 | }; 56 | 57 | // A non-Xunit Fact attribute is present (using statement). 58 | yield return new object[] 59 | { 60 | @"using UnitTestAnalyzers.Test.Attributes; 61 | class ClassNameTests 62 | { 63 | [Fact] 64 | public void Test1() {} 65 | }", 66 | TestSettingsData.XunitTestSettingsSimpleRegex 67 | }; 68 | 69 | // A non-Xunit Theory attribute is present (using statement). 70 | yield return new object[] 71 | { 72 | @"using UnitTestAnalyzers.Test.Attributes; 73 | class ClassNameTests 74 | { 75 | [Theory] 76 | public void Test1() {} 77 | }", 78 | TestSettingsData.XunitTestSettingsSimpleRegex 79 | }; 80 | 81 | // A Xunit Fact attribute is present (using statement) and the method name has the expected format. 82 | // The provided settings does not contain a regex therefore the default format is enforced. 83 | yield return new object[] 84 | { 85 | @"using Xunit; 86 | class ClassName 87 | { 88 | [Fact] 89 | public void TestOne_UsingFoo_ThrowsResult() {} 90 | }", 91 | TestSettingsData.XunitSettings 92 | }; 93 | 94 | // A Xunit Theory attribute is present (using statement) and the method name has the expected format. 95 | // The provided settings does not contain a regex therefore the default format is enforced. 96 | yield return new object[] 97 | { 98 | @"using Xunit; 99 | class ClassName 100 | { 101 | [Theory] 102 | public void TestOne_UsingFoo_ThrowsResult() {} 103 | }", 104 | TestSettingsData.XunitSettings 105 | }; 106 | 107 | // A Xunit Fact attribute is present (fully qualified named) and the method name has the expected format. 108 | // The provided settings does not contain a regex therefore the default format is enforced. 109 | yield return new object[] 110 | { 111 | @" 112 | class ClassName 113 | { 114 | [Xunit.Fact] 115 | public void TestOne_WhenFoo_ExpectsResult() {} 116 | }", 117 | TestSettingsData.XunitSettings 118 | }; 119 | 120 | // A Xunit Theory attribute is present (fully qualified named) and the method name has the expected format. 121 | // The provided settings does not contain a regex therefore the default format is enforced.p 122 | yield return new object[] 123 | { 124 | @" 125 | class ClassName 126 | { 127 | [Xunit.Theory] 128 | public void TestOne_WhenFoo_ExpectsResult() {} 129 | }", 130 | TestSettingsData.XunitSettings 131 | }; 132 | 133 | // A Xunit Fact attribute is present (using statement) and the method name has the expected format. 134 | // Additionally a settings is provided redefining the test name regex. 135 | yield return new object[] 136 | { 137 | @"using Xunit; 138 | class ClassName 139 | { 140 | [Fact] 141 | public void TestOne() {} 142 | }", 143 | TestSettingsData.XunitTestSettingsSimpleRegex 144 | }; 145 | 146 | // A Xunit Theory attribute is present (using statement) and the method name has the expected format. 147 | // Additionally a settings is provided redefining the test name regex. 148 | yield return new object[] 149 | { 150 | @"using Xunit; 151 | class ClassName 152 | { 153 | [Theory] 154 | public void TestOne() {} 155 | }", 156 | TestSettingsData.XunitTestSettingsSimpleRegex 157 | }; 158 | } 159 | 160 | IEnumerator IEnumerable.GetEnumerator() 161 | { 162 | return this.GetEnumerator(); 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseUnitTestsSuffixMSTestInvalidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseUnitTestsSuffixMSTestInvalidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // A MSTest TestClass attribute is present (using statement) and the class name does not have the expected suffix. 11 | yield return new object[] 12 | { 13 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 14 | [TestClass] 15 | class ClassName 16 | {}", 17 | "ClassName", // Diagnostic message paramater 18 | 3, // Violation line 19 | 7, // Violation column. 20 | TestSettingsData.NoSettings 21 | }; 22 | 23 | // A MSTest TestClass attribute is present (fully qualified name) and the class name does not have the expected suffix. 24 | yield return new object[] 25 | { 26 | @" 27 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestClass] 28 | class ClassNameTests 29 | {}", 30 | "ClassNameTests", 31 | 3, 32 | 7, 33 | TestSettingsData.NoSettings 34 | }; 35 | 36 | // A MSTest TestClass attribute is grouped along with another attribute and the class name does not have the suffix. 37 | yield return new object[] 38 | { 39 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 40 | [MyAttribute, TestClass] 41 | class ClassNameFunctionalTests 42 | {}", 43 | "ClassNameFunctionalTests", 44 | 3, 45 | 7, 46 | TestSettingsData.NoSettings 47 | }; 48 | 49 | // A MSTest TestClass attribute is present along with another attribute and the class name does not have the expected suffix. 50 | yield return new object[] 51 | { 52 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 53 | [MyAttribute] 54 | [TestClass] 55 | class ClassNameUnitTest 56 | {}", 57 | "ClassNameUnitTest", 58 | 4, 59 | 7, 60 | TestSettingsData.NoSettings 61 | }; 62 | 63 | // A MSTest TestClass attribute is present along with another attribute and the class name does not have the expected suffix. 64 | // Additionally a configuration settings is provided to indicate the test framework to be used. 65 | yield return new object[] 66 | { 67 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 68 | [MyAttribute] 69 | [TestClass] 70 | class ClassNameUnitTest 71 | {}", 72 | "ClassNameUnitTest", 73 | 4, 74 | 7, 75 | TestSettingsData.MSTestSettings 76 | }; 77 | 78 | // A MSTest TestClass attribute is present along with another attribute and the class name does not have the expected suffix. 79 | // Additionally a configuration settings is provided with a bad format. The analyzer should default to the MsTest framework in that case. 80 | yield return new object[] 81 | { 82 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 83 | [MyAttribute] 84 | [TestClass] 85 | class ClassNameUnitTest 86 | {}", 87 | "ClassNameUnitTest", 88 | 4, 89 | 7, 90 | TestSettingsData.InvalidSettings 91 | }; 92 | } 93 | 94 | IEnumerator IEnumerable.GetEnumerator() 95 | { 96 | return this.GetEnumerator(); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseUnitTestsSuffixMSTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseUnitTestsSuffixMSTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // No class attribute present. 11 | yield return new[] { @"class ClassName {}", TestSettingsData.NoSettings }; 12 | 13 | // A random class attribute present. 14 | yield return new[] 15 | { 16 | @" 17 | [MyAttribute] 18 | class ClassName 19 | {}", 20 | TestSettingsData.NoSettings 21 | }; 22 | 23 | // Multiple random class attributes present. 24 | yield return new[] 25 | { 26 | @" 27 | [MyAttributeOne] 28 | [MyAttributeTwo] 29 | class ClassName 30 | {}", 31 | TestSettingsData.NoSettings 32 | }; 33 | 34 | // A non-MSTest TestClass attribute present (fully qualified name). 35 | yield return new[] 36 | { 37 | @" 38 | [UnitTestAnalyzers.Test.Attributes.TestClass] 39 | class ClassName 40 | {}", 41 | TestSettingsData.NoSettings 42 | }; 43 | 44 | // A non-MSTest TestClass attribute present (using statement). 45 | yield return new[] 46 | { 47 | @"using UnitTestAnalyzers.Test.Attributes; 48 | [TestClass] 49 | class ClassName 50 | {}", 51 | TestSettingsData.NoSettings 52 | }; 53 | 54 | // A MSTest TestClass attribute is present (using statement) and the class name has the expected suffix. 55 | yield return new[] 56 | { 57 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 58 | [TestClass] 59 | class ClassNameUnitTests 60 | {}", 61 | TestSettingsData.NoSettings 62 | }; 63 | 64 | // A MSTest TestClass attribute is present (fully qualified name) and the class name has the expected suffix. 65 | yield return new[] 66 | { 67 | @" 68 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestClass] 69 | class ClassNameUnitTests 70 | {}", 71 | TestSettingsData.NoSettings 72 | }; 73 | 74 | // A MSTest TestClass attribute is present (fully qualified name) and the class name has the expected suffix. 75 | // Additionally a configuration settings is provided indicating that the test framework is MsTest. 76 | yield return new[] 77 | { 78 | @" 79 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestClass] 80 | class ClassNameUnitTests 81 | {}", 82 | TestSettingsData.MSTestSettings 83 | }; 84 | 85 | // A MSTest TestClass attribute is present (fully qualified name) and the class name has the expected suffix. 86 | // Additionally a configuration settings with bad format is provided. The analyzer should default the framework to MsTest. 87 | yield return new[] 88 | { 89 | @" 90 | [Microsoft.VisualStudio.TestTools.UnitTesting.TestClass] 91 | class ClassNameUnitTests 92 | {}", 93 | TestSettingsData.InvalidSettings 94 | }; 95 | 96 | // A MSTest TestClass attribute is grouped along with another attribute and the class name has the expected suffix. 97 | yield return new[] 98 | { 99 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 100 | [MyAttribute, TestClass] 101 | class ClassNameUnitTests 102 | {}", 103 | TestSettingsData.NoSettings 104 | }; 105 | 106 | // A MSTest TestClass attribute is present along with another attribute and the class name has the expected suffix. 107 | yield return new[] 108 | { 109 | @"using Microsoft.VisualStudio.TestTools.UnitTesting; 110 | [MyAttribute] 111 | [TestClass] 112 | class ClassNameUnitTests 113 | {}", 114 | TestSettingsData.NoSettings 115 | }; 116 | } 117 | 118 | IEnumerator IEnumerable.GetEnumerator() 119 | { 120 | return this.GetEnumerator(); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseUnitTestsSuffixNUnitTestInvalidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseUnitTestsSuffixNUnitTestInvalidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // The class contains an NUnit Test method (using namespace) and the class name does not have the expected suffix. 11 | yield return new object[] 12 | { 13 | @"using NUnit.Framework; 14 | class ClassName 15 | { 16 | [Test] 17 | public void TestMethod() {} 18 | }", 19 | "ClassName", // Diagnostic message parameter 20 | 2, // Violation line 21 | 7, // Violation column. 22 | TestSettingsData.NUnitSettings 23 | }; 24 | 25 | // The class contains an NUnit TestCase method (using namespace) and the class name does not have the expected suffix. 26 | yield return new object[] 27 | { 28 | @"using NUnit.Framework; 29 | class ClassName 30 | { 31 | [TestCase] 32 | public void TestMethod() {} 33 | }", 34 | "ClassName", 35 | 2, 36 | 7, 37 | TestSettingsData.NUnitSettings 38 | }; 39 | 40 | // The class contains an NUnit Test method (fully qualified name) and the class name does not have the expected suffix. 41 | yield return new object[] 42 | { 43 | @" 44 | class ClassName 45 | { 46 | [NUnit.Framework.Test] 47 | public void TestMethod() {} 48 | }", 49 | "ClassName", 50 | 2, 51 | 7, 52 | TestSettingsData.NUnitSettings 53 | }; 54 | 55 | // The class contains an NUnit TestCase method (fully qualified name) and the class name does not have the expected suffix. 56 | yield return new object[] 57 | { 58 | @" 59 | class ClassName 60 | { 61 | [NUnit.Framework.TestCase] 62 | public void TestMethod() {} 63 | }", 64 | "ClassName", 65 | 2, 66 | 7, 67 | TestSettingsData.NUnitSettings 68 | }; 69 | 70 | // A Test attribute is grouped along with another attribute and the class name does not have the expected suffix. 71 | yield return new object[] 72 | { 73 | @"using NUnit.Framework; 74 | class ClassNameFunctionalTests 75 | { 76 | [Test, MyAttribute] 77 | public void TestMethod() {} 78 | }", 79 | "ClassNameFunctionalTests", 80 | 2, 81 | 7, 82 | TestSettingsData.NUnitSettings 83 | }; 84 | 85 | // A TestCase attribute is grouped along with another attribute and the class name does not have the expected suffix. 86 | yield return new object[] 87 | { 88 | @"using NUnit.Framework; 89 | class ClassNameFunctionalTests 90 | { 91 | [TestCase, MyAttribute] 92 | public void TestMethod() {} 93 | }", 94 | "ClassNameFunctionalTests", 95 | 2, 96 | 7, 97 | TestSettingsData.NUnitSettings 98 | }; 99 | 100 | // A Test attribute is present along with another attribute and the class name does not have the expected suffix. 101 | yield return new object[] 102 | { 103 | @"using NUnit.Framework; 104 | class ClassNameFunctionalTests 105 | { 106 | [Test] 107 | [MyAttribute] 108 | public void TestMethod() {} 109 | }", 110 | "ClassNameFunctionalTests", 111 | 2, 112 | 7, 113 | TestSettingsData.NUnitSettings 114 | }; 115 | 116 | // A TestCase attribute is present along with another attribute and the class name does not have the expected suffix. 117 | yield return new object[] 118 | { 119 | @"using NUnit.Framework; 120 | class ClassNameFunctionalTests 121 | { 122 | [TestCase] 123 | [MyAttribute] 124 | public void TestMethod() {} 125 | }", 126 | "ClassNameFunctionalTests", 127 | 2, 128 | 7, 129 | TestSettingsData.NUnitSettings 130 | }; 131 | 132 | // A class contains other method in addition to a Test method and the class name does not have the expected suffix. 133 | yield return new object[] 134 | { 135 | @"using NUnit.Framework; 136 | class ClassNameFunctionalTests 137 | { 138 | public void AnotherMethod() {} 139 | [Test] 140 | public void TestMethod() {} 141 | }", 142 | "ClassNameFunctionalTests", 143 | 2, 144 | 7, 145 | TestSettingsData.NUnitSettings 146 | }; 147 | 148 | // A class contains other method in addition to a TestCase method and the class name does not have the expected suffix. 149 | yield return new object[] 150 | { 151 | @"using NUnit.Framework; 152 | class ClassNameFunctionalTests 153 | { 154 | [TestCase] 155 | [MyAttribute] 156 | public void TestMethod() {} 157 | 158 | public void AnotherMethod() {} 159 | }", 160 | "ClassNameFunctionalTests", 161 | 2, 162 | 7, 163 | TestSettingsData.NUnitSettings 164 | }; 165 | } 166 | 167 | IEnumerator IEnumerable.GetEnumerator() 168 | { 169 | return this.GetEnumerator(); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseUnitTestsSuffixNUnitTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseUnitTestsSuffixNUnitTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // No method in class. 11 | yield return new[] { @"class ClassName {}", TestSettingsData.NUnitSettings }; 12 | 13 | // No test method (Test or TestCase) in class. A method is present without any attribute. 14 | yield return new[] 15 | { 16 | @" 17 | class ClassName 18 | { 19 | public void SomeMethod() {} 20 | }", 21 | TestSettingsData.NUnitSettings 22 | }; 23 | 24 | // No test method (Test or TestCase) in class. A method is present without some attribute. 25 | yield return new[] 26 | { 27 | @" 28 | class ClassName 29 | { 30 | [MyAttribute] 31 | public void SomeMethod() {} 32 | }", 33 | TestSettingsData.NUnitSettings 34 | }; 35 | 36 | // A non-NUnit Test attribute present (fully qualified name). 37 | yield return new[] 38 | { 39 | @" 40 | class ClassName 41 | { 42 | [UnitTestAnalyzers.Test.Attributes.Test] 43 | public void MyMethod() {} 44 | }", 45 | TestSettingsData.NUnitSettings 46 | }; 47 | 48 | // A non-NUnit TestCase attribute present (fully qualified name). 49 | yield return new[] 50 | { 51 | @" 52 | class ClassName 53 | { 54 | [UnitTestAnalyzers.Test.Attributes.TestCase] 55 | public void MyMethod() {} 56 | }", 57 | TestSettingsData.NUnitSettings 58 | }; 59 | 60 | // A non-NUnit Test attribute present (using statement). 61 | yield return new[] 62 | { 63 | @"using UnitTestAnalyzers.Test.Attributes; 64 | class ClassName 65 | { 66 | [Test] 67 | public void MyMethod() {} 68 | }", 69 | TestSettingsData.NUnitSettings 70 | }; 71 | 72 | // A non-NUnit TestCase attribute present (using statement). 73 | yield return new[] 74 | { 75 | @"using UnitTestAnalyzers.Test.Attributes; 76 | class ClassName 77 | { 78 | [TestCase] 79 | public void MyMethod() {} 80 | }", 81 | TestSettingsData.NUnitSettings 82 | }; 83 | 84 | // A NUnit Test method is present (fully qualified name) and the class name has the expected suffix. 85 | yield return new[] 86 | { 87 | @" 88 | class ClassNameUnitTests 89 | { 90 | [NUnit.Framework.Test] 91 | public void TestMethod() {} 92 | }", 93 | TestSettingsData.NUnitSettings 94 | }; 95 | 96 | // A NUnit TestCase method is present (fully qualified name) and the class name has the expected suffix. 97 | yield return new[] 98 | { 99 | @" 100 | class ClassNameUnitTests 101 | { 102 | [NUnit.Framework.TestCase] 103 | public void TestMethod() {} 104 | }", 105 | TestSettingsData.NUnitSettings 106 | }; 107 | } 108 | 109 | IEnumerator IEnumerable.GetEnumerator() 110 | { 111 | return this.GetEnumerator(); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseUnitTestsSuffixXunitTestValidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseUnitTestsSuffixXunitTestValidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // No method in class. 11 | yield return new[] { @"class ClassName {}", TestSettingsData.XunitSettings }; 12 | 13 | // No test method (Fact or Theory) in class. A method is present without any attribute. 14 | yield return new[] 15 | { 16 | @" 17 | class ClassName 18 | { 19 | public void SomeMethod() {} 20 | }", 21 | TestSettingsData.XunitSettings 22 | }; 23 | 24 | // No test method (Fact or Theory) in class. A method is present without some attribute. 25 | yield return new[] 26 | { 27 | @" 28 | class ClassName 29 | { 30 | [MyAttribute] 31 | public void SomeMethod() {} 32 | }", 33 | TestSettingsData.XunitSettings 34 | }; 35 | 36 | // A non-xUnit Fact attribute present (fully qualified name). 37 | yield return new[] 38 | { 39 | @" 40 | class ClassName 41 | { 42 | [UnitTestAnalyzers.Test.Attributes.Fact] 43 | public void MyMethod() {} 44 | }", 45 | TestSettingsData.XunitSettings 46 | }; 47 | 48 | // A non-xUnit Theory attribute present (fully qualified name). 49 | yield return new[] 50 | { 51 | @" 52 | class ClassName 53 | { 54 | [UnitTestAnalyzers.Test.Attributes.Theory] 55 | public void MyMethod() {} 56 | }", 57 | TestSettingsData.XunitSettings 58 | }; 59 | 60 | // A non-xUnit Fact attribute present (using statement). 61 | yield return new[] 62 | { 63 | @"using UnitTestAnalyzers.Test.Attributes; 64 | class ClassName 65 | { 66 | [Fact] 67 | public void MyMethod() {} 68 | }", 69 | TestSettingsData.XunitSettings 70 | }; 71 | 72 | // A non-xUnit Theory attribute present (using statement). 73 | yield return new[] 74 | { 75 | @"using UnitTestAnalyzers.Test.Attributes; 76 | class ClassName 77 | { 78 | [Theory] 79 | public void MyMethod() {} 80 | }", 81 | TestSettingsData.XunitSettings 82 | }; 83 | 84 | // A xUnit Fact method is present (fully qualified name) and the class name has the expected suffix. 85 | yield return new[] 86 | { 87 | @" 88 | class ClassNameUnitTests 89 | { 90 | [Xunit.Fact] 91 | public void TestMethod() {} 92 | }", 93 | TestSettingsData.XunitSettings 94 | }; 95 | 96 | // A xUnit Theory method is present (fully qualified name) and the class name has the expected suffix. 97 | yield return new[] 98 | { 99 | @" 100 | class ClassNameUnitTests 101 | { 102 | [Xunit.Theory] 103 | public void TestMethod() {} 104 | }", 105 | TestSettingsData.XunitSettings 106 | }; 107 | } 108 | 109 | IEnumerator IEnumerable.GetEnumerator() 110 | { 111 | return this.GetEnumerator(); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/TestData/UseUnitTestsSuffixxUnitTestInvalidData.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Test.TestData 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | internal class UseUnitTestsSuffixXunitTestInvalidData : IEnumerable 7 | { 8 | public IEnumerator GetEnumerator() 9 | { 10 | // The class contains an xUnit Fact method (using namespace) and the class name does not have the expected suffix. 11 | yield return new object[] 12 | { 13 | @"using Xunit; 14 | class ClassName 15 | { 16 | [Fact] 17 | public void TestMethod() {} 18 | }", 19 | "ClassName", // Diagnostic message parameter 20 | 2, // Violation line 21 | 7, // Violation column. 22 | TestSettingsData.XunitSettings 23 | }; 24 | 25 | // The class contains an xUnit Theory method (using namespace) and the class name does not have the expected suffix. 26 | yield return new object[] 27 | { 28 | @"using Xunit; 29 | class ClassName 30 | { 31 | [Theory] 32 | public void TestMethod() {} 33 | }", 34 | "ClassName", 35 | 2, 36 | 7, 37 | TestSettingsData.XunitSettings 38 | }; 39 | 40 | // The class contains an xUnit Fact method (fully qualified name) and the class name does not have the expected suffix. 41 | yield return new object[] 42 | { 43 | @" 44 | class ClassName 45 | { 46 | [Xunit.Fact] 47 | public void TestMethod() {} 48 | }", 49 | "ClassName", 50 | 2, 51 | 7, 52 | TestSettingsData.XunitSettings 53 | }; 54 | 55 | // The class contains an xUnit Theory method (fully qualified name) and the class name does not have the expected suffix. 56 | yield return new object[] 57 | { 58 | @" 59 | class ClassName 60 | { 61 | [Xunit.Theory] 62 | public void TestMethod() {} 63 | }", 64 | "ClassName", 65 | 2, 66 | 7, 67 | TestSettingsData.XunitSettings 68 | }; 69 | 70 | // A Fact attribute is grouped along with another attribute and the class name does not have the expected suffix. 71 | yield return new object[] 72 | { 73 | @"using Xunit; 74 | class ClassNameFunctionalTests 75 | { 76 | [Fact, MyAttribute] 77 | public void TestMethod() {} 78 | }", 79 | "ClassNameFunctionalTests", 80 | 2, 81 | 7, 82 | TestSettingsData.XunitSettings 83 | }; 84 | 85 | // A Theory attribute is grouped along with another attribute and the class name does not have the expected suffix. 86 | yield return new object[] 87 | { 88 | @"using Xunit; 89 | class ClassNameFunctionalTests 90 | { 91 | [Theory, MyAttribute] 92 | public void TestMethod() {} 93 | }", 94 | "ClassNameFunctionalTests", 95 | 2, 96 | 7, 97 | TestSettingsData.XunitSettings 98 | }; 99 | 100 | // A Fact attribute is present along with another attribute and the class name does not have the expected suffix. 101 | yield return new object[] 102 | { 103 | @"using Xunit; 104 | class ClassNameFunctionalTests 105 | { 106 | [Fact] 107 | [MyAttribute] 108 | public void TestMethod() {} 109 | }", 110 | "ClassNameFunctionalTests", 111 | 2, 112 | 7, 113 | TestSettingsData.XunitSettings 114 | }; 115 | 116 | // A Theory attribute is present along with another attribute and the class name does not have the expected suffix. 117 | yield return new object[] 118 | { 119 | @"using Xunit; 120 | class ClassNameFunctionalTests 121 | { 122 | [Theory] 123 | [MyAttribute] 124 | public void TestMethod() {} 125 | }", 126 | "ClassNameFunctionalTests", 127 | 2, 128 | 7, 129 | TestSettingsData.XunitSettings 130 | }; 131 | 132 | // A class contains other method in addition to a Fact method and the class name does not have the expected suffix. 133 | yield return new object[] 134 | { 135 | @"using Xunit; 136 | class ClassNameFunctionalTests 137 | { 138 | public void AnotherMethod() {} 139 | [Fact] 140 | public void TestMethod() {} 141 | }", 142 | "ClassNameFunctionalTests", 143 | 2, 144 | 7, 145 | TestSettingsData.XunitSettings 146 | }; 147 | 148 | // A class contains other method in addition to a Theory method and the class name does not have the expected suffix. 149 | yield return new object[] 150 | { 151 | @"using Xunit; 152 | class ClassNameFunctionalTests 153 | { 154 | [Theory] 155 | [MyAttribute] 156 | public void TestMethod() {} 157 | 158 | public void AnotherMethod() {} 159 | }", 160 | "ClassNameFunctionalTests", 161 | 2, 162 | 7, 163 | TestSettingsData.XunitSettings 164 | }; 165 | } 166 | 167 | IEnumerator IEnumerable.GetEnumerator() 168 | { 169 | return this.GetEnumerator(); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Test/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Vsix/UnitTestAnalyzers.Vsix.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 14.0 6 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 7 | 8 | 9 | 10 | 11 | 12 | Debug 13 | AnyCPU 14 | 2.0 15 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | {1FB0E60C-FB26-4F04-B766-DFDFCB0EEE5C} 17 | Library 18 | Properties 19 | UnitTestAnalyzers.Vsix 20 | UnitTestAnalyzers.Vsix 21 | v4.5.2 22 | false 23 | false 24 | false 25 | false 26 | false 27 | false 28 | Roslyn 29 | 30 | 31 | true 32 | full 33 | false 34 | bin\Debug\ 35 | DEBUG;TRACE 36 | prompt 37 | 4 38 | 39 | 40 | pdbonly 41 | true 42 | bin\Release\ 43 | TRACE 44 | prompt 45 | 4 46 | 47 | 48 | Program 49 | $(DevEnvDir)devenv.exe 50 | /rootsuffix Roslyn 51 | 52 | 53 | 54 | Designer 55 | 56 | 57 | 58 | 59 | {F5D899DD-0AD6-4480-A0A8-7B5203D7BE9E} 60 | UnitTestAnalyzers 61 | 62 | 63 | 64 | 65 | ..\..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll 66 | True 67 | 68 | 69 | 70 | 71 | 72 | 73 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 74 | 75 | 76 | 77 | 84 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers.Vsix/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | UnitTestAnalyzers 6 | An implementation unit tests analyzers using Roslyn.An implementation of StyleCop's rules using Roslyn analyzers and code fixes 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Design/TestNameMustIncludeMemberUnderTestAnalyzer.cs: -------------------------------------------------------------------------------- 1 |  namespace UnitTestAnalyzers 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Collections.Immutable; 6 | using System.Linq; 7 | using System.Text.RegularExpressions; 8 | using Microsoft.CodeAnalysis; 9 | using Microsoft.CodeAnalysis.CSharp; 10 | using Microsoft.CodeAnalysis.CSharp.Syntax; 11 | using Microsoft.CodeAnalysis.Diagnostics; 12 | using Parsers; 13 | using Settings; 14 | using Settings.ObjectModel; 15 | 16 | /// 17 | /// This analyzer verifies whether a test method name contains the name of the member under test. 18 | /// If the regex provided by the analyzer settings contains a group named with 19 | /// this analyzer will validate that the test is invoking a member that matches the value represented by this group generating a warning if it does not. 20 | /// 21 | /// 22 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 23 | public class TestNameMustIncludeMemberUnderTestAnalyzer : DiagnosticAnalyzer 24 | { 25 | /// 26 | /// The ID for diagnostics produced by the analyzer when the comments are missing, too many or out of order. 27 | /// 28 | public const string DiagnosticId = "TestNameMustIncludeMemberUnderTest"; 29 | private const string Category = "Design"; 30 | 31 | private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.TestMethodNameMustIncludeMemberUnderTestTitle), Resources.ResourceManager, typeof(Resources)); 32 | private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.TestMethodNameMustIncludeMemberUnderTestMessage), Resources.ResourceManager, typeof(Resources)); 33 | private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.TestMethodNameMustIncludeMemberUnderTestDescription), Resources.ResourceManager, typeof(Resources)); 34 | private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description); 35 | 36 | /// 37 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); 38 | 39 | /// 40 | public override void Initialize(AnalysisContext context) 41 | { 42 | context.RegisterCompilationStartAction(HandleCompilationStart); 43 | } 44 | 45 | private static void HandleCompilationStart(CompilationStartAnalysisContext context) 46 | { 47 | AnalyzersSettings settings = SettingsProvider.GetSettings(context); 48 | var unitTestParser = UnitTestParserFactory.Create(settings); 49 | context.RegisterSyntaxNodeAction(c => AnalyzeNode(c, unitTestParser, settings), SyntaxKind.MethodDeclaration); 50 | } 51 | 52 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context, IUnitTestParser parser, AnalyzersSettings settings) 53 | { 54 | if (!parser.IsUnitTestMethod(context)) 55 | { 56 | return; 57 | } 58 | 59 | MethodDeclarationSyntax methodDeclaration = (MethodDeclarationSyntax)context.Node; 60 | 61 | Match match = settings.TestMethodNameFormatRegex.Match(methodDeclaration.Identifier.ToString()); 62 | 63 | string memberUnderTest = match?.Groups[AnalyzersSettings.MemberUnderTestRegexGroupName].Value; 64 | 65 | if (string.IsNullOrWhiteSpace(memberUnderTest)) 66 | { 67 | return; 68 | } 69 | 70 | IEnumerable descendantNodes = methodDeclaration.Body.DescendantNodes(); 71 | if (!descendantNodes?.Any() ?? true) 72 | { 73 | return; 74 | } 75 | 76 | IEnumerable memberAccessExpressions = descendantNodes.OfType(); 77 | IEnumerable ctorExpressions = descendantNodes.OfType(); 78 | if (!memberAccessExpressions.Any() && !ctorExpressions.Any()) 79 | { 80 | return; 81 | } 82 | 83 | if (memberAccessExpressions.Any(memberAccess => string.Equals(memberUnderTest, memberAccess.Name.Identifier.ToString(), StringComparison.Ordinal))) 84 | { 85 | return; 86 | } 87 | 88 | if (ctorExpressions.Any(ctorExpression => string.Equals(memberUnderTest, ctorExpression.Type.ToString(), StringComparison.Ordinal))) 89 | { 90 | return; 91 | } 92 | 93 | var diagnostic = Diagnostic.Create(Rule, methodDeclaration.Identifier.GetLocation(), methodDeclaration.Identifier.ToString(), memberUnderTest); 94 | 95 | context.ReportDiagnostic(diagnostic); 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Documentation/UseAAACommentsAnalyzer.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Collections.Immutable; 6 | using System.Linq; 7 | using Microsoft.CodeAnalysis; 8 | using Microsoft.CodeAnalysis.CSharp; 9 | using Microsoft.CodeAnalysis.CSharp.Syntax; 10 | using Microsoft.CodeAnalysis.Diagnostics; 11 | using Microsoft.CodeAnalysis.Text; 12 | using Parsers; 13 | using Settings; 14 | using Settings.ObjectModel; 15 | 16 | /// 17 | /// This analyzer verifies whether a test method contains the comments // Arrange. // Act. // Assert. 18 | /// and it reports a warning if the comments are missing, too many or out of order. 19 | /// 20 | /// 21 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 22 | public class UseAAACommentsAnalyzer : DiagnosticAnalyzer 23 | { 24 | /// 25 | /// The ID for diagnostics produced by the analyzer when the comments are missing, too many or out of order. 26 | /// 27 | public const string AAACommentsDiagnosticId = "UseAAAComments"; 28 | 29 | /// 30 | /// The ID for diagnostics produced by the analyzer when the comment // Arrange. is not in the 31 | /// first line of the body of the test method. 32 | /// 33 | public const string ArrangeCommentFirstLineDiagnosticId = "UseArrangeCommentAsFirstLine"; 34 | 35 | private const string Category = "Documentation"; 36 | 37 | private static readonly LocalizableString AAACommentsTitle = new LocalizableResourceString(nameof(Resources.UseAAACommentsAnalyzerTitle), Resources.ResourceManager, typeof(Resources)); 38 | private static readonly LocalizableString AAACommentsMessageFormat = new LocalizableResourceString(nameof(Resources.UseAAACommentsAnalyzerMessage), Resources.ResourceManager, typeof(Resources)); 39 | private static readonly LocalizableString AAACommentsDescription = new LocalizableResourceString(nameof(Resources.UseAAACommentsAnalyzerDescription), Resources.ResourceManager, typeof(Resources)); 40 | 41 | private static readonly LocalizableString FirstLineArrangeTitle = new LocalizableResourceString(nameof(Resources.ArrangeCommentMustBeFirstLineTitle), Resources.ResourceManager, typeof(Resources)); 42 | private static readonly LocalizableString FirstLineArrangeMessageFormat = new LocalizableResourceString(nameof(Resources.ArrangeCommentMustBeFirstLineMessage), Resources.ResourceManager, typeof(Resources)); 43 | private static readonly LocalizableString FirstLineArrangeDescription = new LocalizableResourceString(nameof(Resources.ArrangeCommentMustBeFirstLineDescription), Resources.ResourceManager, typeof(Resources)); 44 | 45 | private static readonly DiagnosticDescriptor AAACommentsRule = new DiagnosticDescriptor(AAACommentsDiagnosticId, AAACommentsTitle, AAACommentsMessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: AAACommentsDescription); 46 | private static readonly DiagnosticDescriptor FirstLineArrangeRule = new DiagnosticDescriptor(ArrangeCommentFirstLineDiagnosticId, FirstLineArrangeTitle, FirstLineArrangeMessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: FirstLineArrangeDescription); 47 | 48 | /// 49 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(AAACommentsRule, FirstLineArrangeRule); 50 | 51 | /// 52 | public override void Initialize(AnalysisContext context) 53 | { 54 | context.RegisterCompilationStartAction(HandleCompilationStart); 55 | } 56 | 57 | private static void HandleCompilationStart(CompilationStartAnalysisContext context) 58 | { 59 | AnalyzersSettings settings = SettingsProvider.GetSettings(context); 60 | var unitTestParser = UnitTestParserFactory.Create(settings); 61 | context.RegisterSyntaxNodeAction(c => AnalyzeNode(c, unitTestParser), SyntaxKind.MethodDeclaration); 62 | } 63 | 64 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context, IUnitTestParser parser) 65 | { 66 | if (!parser.IsUnitTestMethod(context)) 67 | { 68 | return; 69 | } 70 | 71 | MethodDeclarationSyntax methodDeclaration = (MethodDeclarationSyntax)context.Node; 72 | 73 | IEnumerable descendantNodes = methodDeclaration.Body.DescendantNodes(); 74 | if (!descendantNodes?.Any() ?? true) 75 | { 76 | return; 77 | } 78 | 79 | IEnumerable memberAccessExpressions = descendantNodes.OfType(); 80 | IEnumerable ctorExpressions = descendantNodes.OfType(); 81 | if (!memberAccessExpressions.Any() && !ctorExpressions.Any()) 82 | { 83 | return; 84 | } 85 | 86 | IEnumerable singleLineComments = methodDeclaration.Body.DescendantTrivia().Where(trivia => trivia.IsKind(SyntaxKind.SingleLineCommentTrivia)); 87 | 88 | IEnumerable arrangeComments = singleLineComments.Where(comment => string.Equals("// Arrange.", comment.ToFullString())); 89 | IEnumerable actComments = singleLineComments.Where(comment => string.Equals("// Act.", comment.ToFullString())); 90 | IEnumerable assertComments = singleLineComments.Where(comment => string.Equals("// Assert.", comment.ToFullString())); 91 | 92 | Diagnostic diagnostic = null; 93 | LinePosition arrangeCommentLine = default(LinePosition); 94 | 95 | if (arrangeComments.Any()) 96 | { 97 | arrangeCommentLine = arrangeComments.First().GetLocation().GetLineSpan().StartLinePosition; 98 | } 99 | 100 | // Check to see whether each comment exists. Only a single instance of each comment should exist. 101 | if (arrangeComments.Count() != 1 || actComments.Count() != 1 || assertComments.Count() != 1) 102 | { 103 | diagnostic = Diagnostic.Create(AAACommentsRule, methodDeclaration.Identifier.GetLocation(), methodDeclaration.Identifier.ToString()); 104 | } 105 | else 106 | { 107 | // Check whether the comments appear with the expected order. 108 | LinePosition actCommentLine = actComments.First().GetLocation().GetLineSpan().StartLinePosition; 109 | LinePosition assertCommentLine = assertComments.First().GetLocation().GetLineSpan().StartLinePosition; 110 | 111 | if (arrangeCommentLine > actCommentLine || actCommentLine > assertCommentLine) 112 | { 113 | diagnostic = Diagnostic.Create(AAACommentsRule, methodDeclaration.Identifier.GetLocation(), methodDeclaration.Identifier.ToString()); 114 | } 115 | } 116 | 117 | if (diagnostic != null) 118 | { 119 | context.ReportDiagnostic(diagnostic); 120 | } 121 | 122 | var methodOpenBrace = methodDeclaration.Body.ChildTokens().FirstOrDefault(token => token.IsKind(SyntaxKind.OpenBraceToken)); 123 | 124 | LinePosition openBraceLinePosition = methodOpenBrace.GetLocation().GetLineSpan().EndLinePosition; 125 | 126 | if (arrangeCommentLine.Line != openBraceLinePosition.Line + 1) 127 | { 128 | diagnostic = Diagnostic.Create(FirstLineArrangeRule, methodDeclaration.Identifier.GetLocation(), methodDeclaration.Identifier.ToString()); 129 | context.ReportDiagnostic(diagnostic); 130 | } 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | 6 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:File must have header", Justification = "")] -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Naming/UseCorrectTestNameFormatAnalyzer.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers 2 | { 3 | using System; 4 | using System.Collections.Immutable; 5 | using System.Linq; 6 | using Microsoft.CodeAnalysis; 7 | using Microsoft.CodeAnalysis.CSharp; 8 | using Microsoft.CodeAnalysis.CSharp.Syntax; 9 | using Microsoft.CodeAnalysis.Diagnostics; 10 | using Parsers; 11 | using Settings; 12 | using Settings.ObjectModel; 13 | 14 | /// 15 | /// This analyzer identifies a test method and reports a warning if the test method name 16 | /// does match the expected format. 17 | /// 18 | /// 19 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 20 | public class UseCorrectTestNameFormatAnalyzer : DiagnosticAnalyzer 21 | { 22 | /// 23 | /// The ID for diagnostics produced by the analyzer. 24 | /// 25 | public const string DiagnosticId = "UseCorrectTestNameFormat"; 26 | private const string Category = "Naming"; 27 | 28 | private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.UseCorrectTestNameFormatTitle), Resources.ResourceManager, typeof(Resources)); 29 | private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.UseCorrectTestNameFormatMessage), Resources.ResourceManager, typeof(Resources)); 30 | private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.UseCorrectTestNameFormatDescription), Resources.ResourceManager, typeof(Resources)); 31 | private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description); 32 | 33 | /// 34 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); 35 | 36 | /// 37 | public override void Initialize(AnalysisContext context) 38 | { 39 | context.RegisterCompilationStartAction(HandleCompilationStart); 40 | } 41 | 42 | private static void HandleCompilationStart(CompilationStartAnalysisContext context) 43 | { 44 | AnalyzersSettings settings = SettingsProvider.GetSettings(context); 45 | IUnitTestParser unitTestParser = UnitTestParserFactory.Create(settings); 46 | context.RegisterSyntaxNodeAction(c => AnalyzeNode(c, unitTestParser, settings), SyntaxKind.MethodDeclaration); 47 | } 48 | 49 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context, IUnitTestParser parser, AnalyzersSettings settings) 50 | { 51 | if (!parser.IsUnitTestMethod(context)) 52 | { 53 | return; 54 | } 55 | 56 | MethodDeclarationSyntax methodDeclaration = (MethodDeclarationSyntax)context.Node; 57 | 58 | var identifier = methodDeclaration.Identifier; 59 | var name = identifier.ToString(); 60 | 61 | if (settings.TestMethodNameFormatRegex.IsMatch(name)) 62 | { 63 | return; 64 | } 65 | 66 | string testNameFormatExamples = settings.TestMethodNameFormatExamples.Any() ? string.Join(", ", settings.TestMethodNameFormatExamples) : AnalyzersSettings.NoTestMethodNameExamplesProvided; 67 | var diagnostic = Diagnostic.Create(Rule, methodDeclaration.Identifier.GetLocation(), methodDeclaration.Identifier.ToString(), settings.TestMethodNameFormat, testNameFormatExamples); 68 | 69 | context.ReportDiagnostic(diagnostic); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Naming/UseUnitTestsSuffixAnalyzer.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers 2 | { 3 | using System; 4 | using System.Collections.Immutable; 5 | using Microsoft.CodeAnalysis; 6 | using Microsoft.CodeAnalysis.CSharp; 7 | using Microsoft.CodeAnalysis.CSharp.Syntax; 8 | using Microsoft.CodeAnalysis.Diagnostics; 9 | using Parsers; 10 | using Settings; 11 | using Settings.ObjectModel; 12 | 13 | /// 14 | /// This analyzer identifies a test class and reports a warning if the test class name 15 | /// does not have the suffic 'UnitTests'. 16 | /// 17 | /// 18 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 19 | public class UseUnitTestsSuffixAnalyzer : DiagnosticAnalyzer 20 | { 21 | /// 22 | /// The ID for diagnostics produced by the analyzer. 23 | /// 24 | public const string DiagnosticId = "UseUnitTestsSuffix"; 25 | private const string Category = "Naming"; 26 | 27 | private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.UseUnitTestsSuffixTitle), Resources.ResourceManager, typeof(Resources)); 28 | private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.UseUnitTestsSuffixMessage), Resources.ResourceManager, typeof(Resources)); 29 | private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.UseUnitTestsSuffixDescription), Resources.ResourceManager, typeof(Resources)); 30 | private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description); 31 | 32 | /// 33 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); 34 | 35 | /// 36 | public override void Initialize(AnalysisContext context) 37 | { 38 | context.RegisterCompilationStartAction(HandleCompilationStart); 39 | } 40 | 41 | private static void HandleCompilationStart(CompilationStartAnalysisContext context) 42 | { 43 | AnalyzersSettings settings = SettingsProvider.GetSettings(context); 44 | IUnitTestParser unitTestParser = UnitTestParserFactory.Create(settings); 45 | context.RegisterSyntaxNodeAction(c => AnalyzeNode(c, unitTestParser), SyntaxKind.ClassDeclaration); 46 | } 47 | 48 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context, IUnitTestParser parser) 49 | { 50 | if (!parser.IsUnitTestClass(context)) 51 | { 52 | return; 53 | } 54 | 55 | ClassDeclarationSyntax classDeclaration = (ClassDeclarationSyntax)context.Node; 56 | 57 | if (classDeclaration.Identifier.ToString().EndsWith("UnitTests")) 58 | { 59 | return; 60 | } 61 | 62 | var diagnostic = Diagnostic.Create(Rule, classDeclaration.Identifier.GetLocation(), classDeclaration.Identifier.ToString()); 63 | 64 | context.ReportDiagnostic(diagnostic); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Parsers/AttributeBasedTestParser.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Parsers 2 | { 3 | using System; 4 | using System.Linq; 5 | using Microsoft.CodeAnalysis; 6 | using Microsoft.CodeAnalysis.CSharp.Syntax; 7 | using Microsoft.CodeAnalysis.Diagnostics; 8 | 9 | /// 10 | /// A base class for test parser based on method attributes 11 | /// 12 | internal abstract class AttributeBasedTestParser : IUnitTestParser 13 | { 14 | /// 15 | /// Return the list of attributes full name used to mark test methods 16 | /// 17 | protected abstract string[] TestMethodAttributes { get; } 18 | 19 | /// 20 | public virtual bool IsUnitTestClass(SyntaxNodeAnalysisContext context) 21 | { 22 | if (context.Node is ClassDeclarationSyntax classDeclaration) 23 | { 24 | var methods = classDeclaration.Members.OfType(); 25 | return methods.Any(x => this.IsUnitTestMethod(context, x)); 26 | } 27 | return false; 28 | } 29 | 30 | /// 31 | public bool IsUnitTestMethod(SyntaxNodeAnalysisContext context) 32 | { 33 | return this.IsUnitTestMethod(context, context.Node as MethodDeclarationSyntax); 34 | } 35 | 36 | private bool IsUnitTestMethod(SyntaxNodeAnalysisContext context, MethodDeclarationSyntax methodDeclaration) 37 | { 38 | var methodAttributes = methodDeclaration?.AttributeLists.SelectMany(a => a.Attributes).ToList(); 39 | 40 | if (!methodAttributes?.Any() ?? true) 41 | { 42 | return false; 43 | } 44 | 45 | if (methodAttributes.Any(methodAttribute => this.IsTestMethodAttribute(context, methodAttribute))) 46 | { 47 | return true; 48 | } 49 | 50 | return false; 51 | } 52 | 53 | private bool IsTestMethodAttribute(SyntaxNodeAnalysisContext context, AttributeSyntax attribute) 54 | { 55 | var attributeName = attribute.Name.ToString(); 56 | 57 | if (this.TestMethodAttributes.Any(x => x.EndsWith(attributeName, StringComparison.Ordinal) || x.EndsWith(attributeName + "Attribute", StringComparison.Ordinal)) == false) 58 | { 59 | return false; 60 | } 61 | 62 | var attributeSymbol = context.SemanticModel.GetSymbolInfo(attribute).Symbol as IMethodSymbol; 63 | 64 | var attributeSymbolName = attributeSymbol?.ToString(); 65 | 66 | if (string.IsNullOrWhiteSpace(attributeSymbolName)) 67 | { 68 | return false; 69 | } 70 | 71 | 72 | return this.TestMethodAttributes.Any(x => attributeSymbolName.StartsWith(x, StringComparison.Ordinal)); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Parsers/IUnitTestParser.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Parsers 2 | { 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | 5 | /// 6 | /// The parser interface for various unit test frameworks. 7 | /// Different unit test frameworks use different attributes and templates to represent test classes and methods 8 | /// 9 | internal interface IUnitTestParser 10 | { 11 | /// 12 | /// Determines whether the specified context refers to a unit test class. 13 | /// 14 | /// The context. 15 | /// 16 | /// if the is a unit test class otherwise, . 17 | /// 18 | bool IsUnitTestClass(SyntaxNodeAnalysisContext context); 19 | 20 | /// 21 | /// Determines whether the specified context refers to a unit test class. 22 | /// 23 | /// The context. 24 | /// 25 | /// if the is a unit test class otherwise, . 26 | /// 27 | bool IsUnitTestMethod(SyntaxNodeAnalysisContext context); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Parsers/MSTestParser.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Parsers 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Microsoft.CodeAnalysis; 7 | using Microsoft.CodeAnalysis.CSharp.Syntax; 8 | using Microsoft.CodeAnalysis.Diagnostics; 9 | 10 | /// 11 | /// Evaluates analysis contexts determining if it represents MSTest elements according to the 12 | /// presence of MSTest attributes. 13 | /// 14 | /// 15 | internal class MSTestParser : AttributeBasedTestParser 16 | { 17 | /// 18 | protected override string[] TestMethodAttributes { get; } = { 19 | "Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute" 20 | }; 21 | 22 | /// 23 | public override bool IsUnitTestClass(SyntaxNodeAnalysisContext context) 24 | { 25 | ClassDeclarationSyntax classDeclaration = context.Node as ClassDeclarationSyntax; 26 | 27 | IEnumerable attributes = classDeclaration?.AttributeLists.SelectMany(x => x.Attributes).ToList(); 28 | 29 | if (!attributes?.Any() ?? true) 30 | { 31 | return false; 32 | } 33 | 34 | AttributeSyntax testClassAttribute = attributes.FirstOrDefault(x => x.Name.ToString().EndsWith("TestClass", StringComparison.Ordinal)); 35 | 36 | if (testClassAttribute == null) 37 | { 38 | return false; 39 | } 40 | 41 | var attributeSymbol = context.SemanticModel.GetSymbolInfo(testClassAttribute).Symbol as IMethodSymbol; 42 | 43 | return attributeSymbol?.ToString().StartsWith("Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute", StringComparison.Ordinal) ?? false; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Parsers/NUnitTestParser.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Parsers 2 | { 3 | using System; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | 6 | /// 7 | /// Evaluates analysis contexts determining if it represents NUnit elements according to the 8 | /// presence of NUnit attributes. 9 | /// 10 | internal class NUnitTestParser: AttributeBasedTestParser 11 | { 12 | /// 13 | protected override string[] TestMethodAttributes { get; } = new[] 14 | { 15 | "NUnit.Framework.TestAttribute", 16 | "NUnit.Framework.TestCaseAttribute", 17 | "NUnit.Framework.TestCaseSourceAttribute", 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Parsers/UnitTestParserFactory.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Parsers 2 | { 3 | using System; 4 | using Settings.ObjectModel; 5 | 6 | internal static class UnitTestParserFactory 7 | { 8 | public static IUnitTestParser Create(AnalyzersSettings settings) 9 | { 10 | switch (settings.UnitTestFramework) 11 | { 12 | case UnitTestFramework.MSTest: 13 | return new MSTestParser(); 14 | case UnitTestFramework.Xunit: 15 | return new XunitTestParser(); 16 | case UnitTestFramework.NUnit: 17 | return new NUnitTestParser(); 18 | default: 19 | throw new NotSupportedException(); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Parsers/XUnitTestParser.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Parsers 2 | { 3 | /// 4 | /// Evaluates analysis contexts determining if it represents Xunit elements according to the 5 | /// presence of Xunit attributes. 6 | /// 7 | /// 8 | internal class XunitTestParser : AttributeBasedTestParser 9 | { 10 | /// 11 | protected override string[] TestMethodAttributes { get; } = { 12 | "Xunit.FactAttribute", 13 | "Xunit.TheoryAttribute" 14 | }; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: AssemblyTitle("UnitTestAnalyzers")] 5 | [assembly: AssemblyProduct("UnitTestAnalyzers")] 6 | [assembly: AssemblyCopyright("Copyright © 2016")] 7 | 8 | [assembly: ComVisible(false)] 9 | 10 | [assembly: AssemblyVersion("1.0.0.0")] 11 | [assembly: AssemblyFileVersion("1.0.0.0")] 12 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace UnitTestAnalyzers { 12 | using System; 13 | using System.Reflection; 14 | 15 | 16 | /// 17 | /// A strongly-typed resource class, for looking up localized strings, etc. 18 | /// 19 | // This class was auto-generated by the StronglyTypedResourceBuilder 20 | // class via a tool like ResGen or Visual Studio. 21 | // To add or remove a member, edit your .ResX file then rerun ResGen 22 | // with the /str option, or rebuild your VS project. 23 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 24 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 25 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 26 | internal class Resources { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() { 34 | } 35 | 36 | /// 37 | /// Returns the cached ResourceManager instance used by this class. 38 | /// 39 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 40 | internal static global::System.Resources.ResourceManager ResourceManager { 41 | get { 42 | if (object.ReferenceEquals(resourceMan, null)) { 43 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UnitTestAnalyzers.Resources", typeof(Resources).GetTypeInfo().Assembly); 44 | resourceMan = temp; 45 | } 46 | return resourceMan; 47 | } 48 | } 49 | 50 | /// 51 | /// Overrides the current thread's CurrentUICulture property for all 52 | /// resource lookups using this strongly typed resource class. 53 | /// 54 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 55 | internal static global::System.Globalization.CultureInfo Culture { 56 | get { 57 | return resourceCulture; 58 | } 59 | set { 60 | resourceCulture = value; 61 | } 62 | } 63 | 64 | /// 65 | /// Looks up a localized string similar to The first line within the test body must be the comment '// Arrange.' . 66 | /// 67 | internal static string ArrangeCommentMustBeFirstLineDescription { 68 | get { 69 | return ResourceManager.GetString("ArrangeCommentMustBeFirstLineDescription", resourceCulture); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized string similar to The body of the unit test '{0}' does not have its first line with the comment '// Arrange.'. 75 | /// 76 | internal static string ArrangeCommentMustBeFirstLineMessage { 77 | get { 78 | return ResourceManager.GetString("ArrangeCommentMustBeFirstLineMessage", resourceCulture); 79 | } 80 | } 81 | 82 | /// 83 | /// Looks up a localized string similar to The first line of the body of a unit test must be '// Arrange.'. 84 | /// 85 | internal static string ArrangeCommentMustBeFirstLineTitle { 86 | get { 87 | return ResourceManager.GetString("ArrangeCommentMustBeFirstLineTitle", resourceCulture); 88 | } 89 | } 90 | 91 | /// 92 | /// Looks up a localized string similar to Unit test method names should include the name of the member under test. 93 | /// 94 | internal static string TestMethodNameMustIncludeMemberUnderTestDescription { 95 | get { 96 | return ResourceManager.GetString("TestMethodNameMustIncludeMemberUnderTestDescription", resourceCulture); 97 | } 98 | } 99 | 100 | /// 101 | /// Looks up a localized string similar to The unit test method '{0}' is targeting the member '{1}' which is not found within the test method body. 102 | /// 103 | internal static string TestMethodNameMustIncludeMemberUnderTestMessage { 104 | get { 105 | return ResourceManager.GetString("TestMethodNameMustIncludeMemberUnderTestMessage", resourceCulture); 106 | } 107 | } 108 | 109 | /// 110 | /// Looks up a localized string similar to Include the member under test in the test method name. 111 | /// 112 | internal static string TestMethodNameMustIncludeMemberUnderTestTitle { 113 | get { 114 | return ResourceManager.GetString("TestMethodNameMustIncludeMemberUnderTestTitle", resourceCulture); 115 | } 116 | } 117 | 118 | /// 119 | /// Looks up a localized string similar to Document the body of the test method with the AAA (Arrange.Act.Assert.) comments. 120 | /// 121 | internal static string UseAAACommentsAnalyzerDescription { 122 | get { 123 | return ResourceManager.GetString("UseAAACommentsAnalyzerDescription", resourceCulture); 124 | } 125 | } 126 | 127 | /// 128 | /// Looks up a localized string similar to The body of the unit test method '{0}' must include the following comments // Arrange. // Act. // Assert. on this order. 129 | /// 130 | internal static string UseAAACommentsAnalyzerMessage { 131 | get { 132 | return ResourceManager.GetString("UseAAACommentsAnalyzerMessage", resourceCulture); 133 | } 134 | } 135 | 136 | /// 137 | /// Looks up a localized string similar to Use the comments // Arrange. // Act. // Assert.. 138 | /// 139 | internal static string UseAAACommentsAnalyzerTitle { 140 | get { 141 | return ResourceManager.GetString("UseAAACommentsAnalyzerTitle", resourceCulture); 142 | } 143 | } 144 | 145 | /// 146 | /// Looks up a localized string similar to Unit test method names should match the expected format. 147 | /// 148 | internal static string UseCorrectTestNameFormatDescription { 149 | get { 150 | return ResourceManager.GetString("UseCorrectTestNameFormatDescription", resourceCulture); 151 | } 152 | } 153 | 154 | /// 155 | /// Looks up a localized string similar to The unit test method '{0}' does not match the expected format '{1}', for instance '{2}'. 156 | /// 157 | internal static string UseCorrectTestNameFormatMessage { 158 | get { 159 | return ResourceManager.GetString("UseCorrectTestNameFormatMessage", resourceCulture); 160 | } 161 | } 162 | 163 | /// 164 | /// Looks up a localized string similar to Use the correct test name format. 165 | /// 166 | internal static string UseCorrectTestNameFormatTitle { 167 | get { 168 | return ResourceManager.GetString("UseCorrectTestNameFormatTitle", resourceCulture); 169 | } 170 | } 171 | 172 | /// 173 | /// Looks up a localized string similar to Unit test class names should end with 'UnitTests'. 174 | /// 175 | internal static string UseUnitTestsSuffixDescription { 176 | get { 177 | return ResourceManager.GetString("UseUnitTestsSuffixDescription", resourceCulture); 178 | } 179 | } 180 | 181 | /// 182 | /// Looks up a localized string similar to The unit test class name '{0}' should end with 'UnitTests'.. 183 | /// 184 | internal static string UseUnitTestsSuffixMessage { 185 | get { 186 | return ResourceManager.GetString("UseUnitTestsSuffixMessage", resourceCulture); 187 | } 188 | } 189 | 190 | /// 191 | /// Looks up a localized string similar to Use 'UnitTests' suffix. 192 | /// 193 | internal static string UseUnitTestsSuffixTitle { 194 | get { 195 | return ResourceManager.GetString("UseUnitTestsSuffixTitle", resourceCulture); 196 | } 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | The first line within the test body must be the comment '// Arrange.' 122 | 123 | 124 | The body of the unit test '{0}' does not have its first line with the comment '// Arrange.' 125 | 126 | 127 | The first line of the body of a unit test must be '// Arrange.' 128 | 129 | 130 | Unit test method names should include the name of the member under test 131 | 132 | 133 | The unit test method '{0}' is targeting the member '{1}' which is not found within the test method body 134 | 135 | 136 | Include the member under test in the test method name 137 | 138 | 139 | Document the body of the test method with the AAA (Arrange.Act.Assert.) comments 140 | 141 | 142 | The body of the unit test method '{0}' must include the following comments // Arrange. // Act. // Assert. on this order 143 | 144 | 145 | Use the comments // Arrange. // Act. // Assert. 146 | 147 | 148 | Unit test method names should match the expected format 149 | 150 | 151 | The unit test method '{0}' does not match the expected format '{1}', for instance '{2}' 152 | 153 | 154 | Use the correct test name format 155 | 156 | 157 | Unit test class names should end with 'UnitTests' 158 | 159 | 160 | The unit test class name '{0}' should end with 'UnitTests'. 161 | 162 | 163 | Use 'UnitTests' suffix 164 | 165 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Settings/ObjectModel/AnalyzersSettings.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Settings.ObjectModel 2 | { 3 | using System.Collections.Immutable; 4 | using System.Text.RegularExpressions; 5 | using Newtonsoft.Json; 6 | using Newtonsoft.Json.Converters; 7 | 8 | /// 9 | /// Represents the settings file used by the analyzer. 10 | /// 11 | [JsonObject(MemberSerialization.OptIn)] 12 | public class AnalyzersSettings 13 | { 14 | /// 15 | /// The format of the test name describing a matching example for the . 16 | /// 17 | public const string DefaultFormat = "(MemberUnderTestName)_(When[a-zA-Z])[0...n]_(Using[a-zA-Z])[0...n]_([Expects|Throws][a-zA-Z])"; 18 | 19 | /// 20 | /// String used in the diagnostic warning produced by when no examples are provided 21 | /// in the analyzer settings file. 22 | /// 23 | public static readonly string NoTestMethodNameExamplesProvided = "NO TEST NAME EXAMPLES PROVIDED!"; 24 | 25 | /// 26 | /// The group name of the regex used to validate test names . 27 | /// If the provided regex contains a group with this name then the test must invoke a member whose name matches the 28 | /// part of the test name represented by this group. 29 | /// 30 | /// 31 | internal const string MemberUnderTestRegexGroupName = "memberUnderTestName"; 32 | 33 | /// 34 | /// The default regex used to validate test name formats. 35 | /// This is the regex that will be used when one is not provided in the analyzer settings file. 36 | /// 37 | internal static readonly Regex DefaultRegex = new Regex($@"\b(?=(?:.*?_){{2,}})(?<{MemberUnderTestRegexGroupName}>[a-zA-Z]+)(?:_When[A-Z]+[a-zA-Z0-9]+)*(?:_Using[A-Z]+[a-zA-Z]+)*(?:_Expects|_Throws)[A-Z]+[a-zA-Z]+\b"); 38 | 39 | /// 40 | /// This is the backing field for the property. 41 | /// 42 | [JsonProperty("unitTestFramework", DefaultValueHandling = DefaultValueHandling.Include)] 43 | [JsonConverter(typeof(StringEnumConverter))] 44 | private UnitTestFramework unitTestFramework; 45 | 46 | /// 47 | /// This is the backing field for the property. 48 | /// 49 | [JsonProperty("testMethodNameFormatRegex", DefaultValueHandling = DefaultValueHandling.Include)] 50 | private Regex testMethodNameFormatRegex; 51 | 52 | /// 53 | /// This is the backing field for the property. 54 | /// 55 | [JsonProperty("testMethodNameFormat", DefaultValueHandling = DefaultValueHandling.Include)] 56 | private string testMethodNameFormat; 57 | 58 | /// 59 | /// This is the backing field for the property. 60 | /// 61 | [JsonProperty("testMethodNameFormatExamples", DefaultValueHandling = DefaultValueHandling.Include)] 62 | private ImmutableArray.Builder testMethodNameFormatExamples; 63 | 64 | /// 65 | /// Initializes a new instance of the class. 66 | /// 67 | [JsonConstructor] 68 | internal AnalyzersSettings() 69 | { 70 | this.unitTestFramework = UnitTestFramework.MSTest; 71 | this.testMethodNameFormatExamples = ImmutableArray.Empty.ToBuilder(); 72 | this.testMethodNameFormatRegex = DefaultRegex; 73 | this.testMethodNameFormat = DefaultFormat; 74 | } 75 | 76 | /// 77 | /// Gets the test method name examples that are valid for the default regex. 78 | /// 79 | /// 80 | public static string[] TestMethodNameFormatDefaultRegexExamples => new[] { "TestMethod_WhenFoo_ExpectsResult", "TestMethod_UsingFoo_ThrowsError" }; 81 | 82 | /// 83 | /// Gets the unit test framework. 84 | /// 85 | internal UnitTestFramework UnitTestFramework => this.unitTestFramework; 86 | 87 | /// 88 | /// Gets the test method name format regex. 89 | /// 90 | internal Regex TestMethodNameFormatRegex => this.testMethodNameFormatRegex; 91 | 92 | /// 93 | /// Gets the test method name format. 94 | /// 95 | internal string TestMethodNameFormat => this.testMethodNameFormat; 96 | 97 | /// 98 | /// Gets the test method name format examples. 99 | /// 100 | internal ImmutableArray.Builder TestMethodNameFormatExamples => this.testMethodNameFormatExamples; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Settings/ObjectModel/SettingsFile.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Settings.ObjectModel 2 | { 3 | using Newtonsoft.Json; 4 | 5 | /// 6 | /// Represents the settings file containing the . 7 | /// 8 | [JsonObject(MemberSerialization.OptIn)] 9 | internal class SettingsFile 10 | { 11 | /// 12 | /// This is the backing field for the property. 13 | /// 14 | [JsonProperty("settings", DefaultValueHandling = DefaultValueHandling.Ignore)] 15 | private readonly AnalyzersSettings settings; 16 | 17 | /// 18 | /// Initializes a new instance of the class 19 | /// during JSON deserialization. 20 | /// 21 | [JsonConstructor] 22 | private SettingsFile() 23 | { 24 | this.settings = new AnalyzersSettings(); 25 | } 26 | 27 | /// 28 | /// Gets the settings. 29 | /// 30 | /// 31 | /// The settings. 32 | /// 33 | internal AnalyzersSettings Settings => this.settings; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Settings/ObjectModel/UnitTestFramework.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Settings.ObjectModel 2 | { 3 | /// 4 | /// Represents the unit test frameworks. 5 | /// 6 | public enum UnitTestFramework 7 | { 8 | /// 9 | /// The MSTest framework. 10 | /// 11 | MSTest, 12 | 13 | /// 14 | /// The Xunit framework. 15 | /// 16 | Xunit, 17 | 18 | /// 19 | /// The NUnit framework 20 | /// 21 | NUnit 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Settings/SettingsProvider.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Settings 2 | { 3 | using System; 4 | using System.Collections.Immutable; 5 | using System.IO; 6 | using System.Runtime.CompilerServices; 7 | using System.Threading; 8 | using Microsoft.CodeAnalysis; 9 | using Microsoft.CodeAnalysis.Diagnostics; 10 | using ObjectModel; 11 | 12 | /// 13 | /// Provides the Analyzer settings retrieving it from the file unittescodeanalysis.json 14 | /// and caches the value for a quicker subsequent access. 15 | /// 16 | internal static class SettingsProvider 17 | { 18 | private const string SettingsFileName = "unittestcodeanalysis.json"; 19 | 20 | private static Tuple, StrongBox> settingsCache = Tuple.Create(new WeakReference(null), new StrongBox(null)); 21 | 22 | #pragma warning disable RS1012 // Start action has no registered actions. 23 | /// 24 | /// Gets the settings. 25 | /// 26 | /// The context. 27 | /// The 28 | internal static AnalyzersSettings GetSettings(CompilationStartAnalysisContext context) 29 | #pragma warning restore RS1012 // Start action has no registered actions. 30 | { 31 | StrongBox cachedSettings = GetOrCreateCachedSettings(context.Compilation); 32 | AnalyzersSettings settings = cachedSettings.Value; 33 | if (settings == null) 34 | { 35 | ImmutableArray additionalFiles = context.Options?.AdditionalFiles ?? ImmutableArray.Create(); 36 | 37 | foreach (AdditionalText additionalFile in additionalFiles) 38 | { 39 | if (string.Equals(Path.GetFileName(additionalFile.Path), SettingsFileName, StringComparison.OrdinalIgnoreCase)) 40 | { 41 | settings = SettingsReader.GetSettings(additionalFile, context.CancellationToken); 42 | break; 43 | } 44 | } 45 | 46 | // If no additional settings file was found use the default settings. 47 | settings = settings ?? new AnalyzersSettings(); 48 | 49 | // If the defaul regex is the one being used (when a regex is not provided in the analyzer settings file then 50 | // use the default examples 51 | if (settings.TestMethodNameFormatRegex.Equals(AnalyzersSettings.DefaultRegex)) 52 | { 53 | settings.TestMethodNameFormatExamples.AddRange(AnalyzersSettings.TestMethodNameFormatDefaultRegexExamples); 54 | } 55 | 56 | cachedSettings.Value = settings; 57 | } 58 | 59 | return settings; 60 | } 61 | 62 | private static StrongBox GetOrCreateCachedSettings(Compilation compilation) 63 | { 64 | var currentSettingsCache = settingsCache; 65 | 66 | Compilation cachedCompilation; 67 | if (!currentSettingsCache.Item1.TryGetTarget(out cachedCompilation) || cachedCompilation != compilation) 68 | { 69 | var replacementCache = Tuple.Create(new WeakReference(compilation), new StrongBox(null)); 70 | while (true) 71 | { 72 | var prior = Interlocked.CompareExchange(ref settingsCache, replacementCache, currentSettingsCache); 73 | 74 | if (prior == currentSettingsCache) 75 | { 76 | currentSettingsCache = replacementCache; 77 | break; 78 | } 79 | 80 | currentSettingsCache = prior; 81 | if (currentSettingsCache.Item1.TryGetTarget(out cachedCompilation) && cachedCompilation == compilation) 82 | { 83 | break; 84 | } 85 | } 86 | } 87 | 88 | return currentSettingsCache.Item2; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/Settings/SettingsReader.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTestAnalyzers.Settings 2 | { 3 | using System.Threading; 4 | using Microsoft.CodeAnalysis; 5 | using Microsoft.CodeAnalysis.Text; 6 | using Newtonsoft.Json; 7 | using ObjectModel; 8 | 9 | /// 10 | /// Reads the unit tests analyzer settings. 11 | /// 12 | internal static class SettingsReader 13 | { 14 | /// 15 | /// Gets the settings. 16 | /// 17 | /// The additional text. 18 | /// The cancellation token. 19 | /// The 20 | internal static AnalyzersSettings GetSettings(AdditionalText additionalText, CancellationToken cancellationToken) 21 | { 22 | SourceText text = additionalText.GetText(cancellationToken); 23 | try 24 | { 25 | SettingsFile settingsRoot = JsonConvert.DeserializeObject(text.ToString()); 26 | 27 | return settingsRoot.Settings; 28 | } 29 | catch (JsonException) 30 | { 31 | // Error deserializing the settings file, will return the default settings instead. 32 | } 33 | 34 | return new AnalyzersSettings(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/UnitTestAnalyzers.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 11.0 6 | Debug 7 | AnyCPU 8 | {F5D899DD-0AD6-4480-A0A8-7B5203D7BE9E} 9 | Library 10 | Properties 11 | UnitTestAnalyzers 12 | UnitTestAnalyzers 13 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | Profile7 15 | v4.5 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | bin\Debug\UnitTestAnalyzers.XML 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | True 50 | True 51 | Resources.resx 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | ResXFileCodeGenerator 62 | Resources.Designer.cs 63 | Designer 64 | 65 | 66 | 67 | 68 | Designer 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | ..\..\packages\Microsoft.CodeAnalysis.Common.1.2.1\lib\portable-net45+win8\Microsoft.CodeAnalysis.dll 82 | True 83 | 84 | 85 | ..\..\packages\Microsoft.CodeAnalysis.CSharp.1.2.1\lib\portable-net45+win8\Microsoft.CodeAnalysis.CSharp.dll 86 | True 87 | 88 | 89 | ..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.2.1\lib\portable-net45+win8\Microsoft.CodeAnalysis.CSharp.Workspaces.dll 90 | True 91 | 92 | 93 | ..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.2.1\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll 94 | True 95 | 96 | 97 | ..\..\packages\Newtonsoft.Json.8.0.3\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll 98 | True 99 | 100 | 101 | ..\..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll 102 | True 103 | 104 | 105 | ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll 106 | True 107 | 108 | 109 | ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll 110 | True 111 | 112 | 113 | ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll 114 | True 115 | 116 | 117 | ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll 118 | True 119 | 120 | 121 | ..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll 122 | True 123 | 124 | 125 | ..\..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll 126 | True 127 | 128 | 129 | 130 | 131 | 138 | -------------------------------------------------------------------------------- /UnitTestAnalyzers/UnitTestAnalyzers/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | --------------------------------------------------------------------------------