Skip to content

Commit 2577970

Browse files
committed
feat: Add provider NSubstituteAnalyzersProvider
1 parent 5184422 commit 2577970

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

src/Atc.CodingRules.AnalyzerProviders/AnalyzerProviderCollector.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public static string[] GetAllBaseRuleProviderNames()
2020
MicrosoftCompilerErrorsProvider.Name,
2121
MicrosoftCompilerErrorsProviderUndocumented.Name,
2222
MicrosoftVisualStudioThreadingAnalyzersProvider.Name,
23+
NSubstituteAnalyzersProvider.Name,
2324
SecurityCodeScanVs2019Provider.Name,
2425
StyleCopAnalyzersProvider.Name,
2526
SonarAnalyzerCSharpProvider.Name,
@@ -57,6 +58,9 @@ public async Task<Collection<AnalyzerProviderBaseRuleData>> CollectAllBaseRules(
5758
var microsoftVisualStudioThreadingAnalyzersProvider = new MicrosoftVisualStudioThreadingAnalyzersProvider(logger, logWithAnsiConsoleMarkup);
5859
var microsoftVisualStudioThreadingAnalyzersProviderTask = microsoftVisualStudioThreadingAnalyzersProvider.CollectBaseRules(ProviderCollectingMode.ReCollect);
5960

61+
var nSubstituteAnalyzersProvider = new NSubstituteAnalyzersProvider(logger, logWithAnsiConsoleMarkup);
62+
var nSubstituteAnalyzersProviderTask = nSubstituteAnalyzersProvider.CollectBaseRules(ProviderCollectingMode.ReCollect);
63+
6064
var securityCodeScanVs2019Provider = new SecurityCodeScanVs2019Provider(logger, logWithAnsiConsoleMarkup);
6165
var securityCodeScanVs2019Task = securityCodeScanVs2019Provider.CollectBaseRules(providerCollectingMode);
6266

@@ -77,6 +81,7 @@ await Task.WhenAll(
7781
microsoftCompilerErrorsTask,
7882
microsoftCompilerErrorsUndocumentedTask,
7983
microsoftVisualStudioThreadingAnalyzersProviderTask,
84+
nSubstituteAnalyzersProviderTask,
8085
securityCodeScanVs2019Task,
8186
styleCopAnalyzersTask,
8287
sonarAnalyzerCSharpTask,
@@ -89,6 +94,7 @@ await Task.WhenAll(
8994
data.Add(await microsoftCompilerErrorsTask);
9095
data.Add(await microsoftCompilerErrorsUndocumentedTask);
9196
data.Add(await microsoftVisualStudioThreadingAnalyzersProviderTask);
97+
data.Add(await nSubstituteAnalyzersProviderTask);
9298
data.Add(await securityCodeScanVs2019Task);
9399
data.Add(await styleCopAnalyzersTask);
94100
data.Add(await sonarAnalyzerCSharpTask);
@@ -120,6 +126,9 @@ public void CacheCleanup()
120126
var microsoftVisualStudioThreadingAnalyzersProvider = new MicrosoftVisualStudioThreadingAnalyzersProvider(logger);
121127
microsoftVisualStudioThreadingAnalyzersProvider.Cleanup();
122128

129+
var nSubstituteAnalyzersProvider = new NSubstituteAnalyzersProvider(logger);
130+
nSubstituteAnalyzersProvider.Cleanup();
131+
123132
var securityCodeScanVs2019Provider = new SecurityCodeScanVs2019Provider(logger);
124133
securityCodeScanVs2019Provider.Cleanup();
125134

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
namespace Atc.CodingRules.AnalyzerProviders.Providers;
2+
3+
public class NSubstituteAnalyzersProvider : AnalyzerProviderBase
4+
{
5+
private const int TableColumnId = 0;
6+
private const int TableColumnCategory = 1;
7+
private const int TableColumnTitle = 2;
8+
9+
public NSubstituteAnalyzersProvider(
10+
ILogger logger,
11+
bool logWithAnsiConsoleMarkup = false)
12+
: base(
13+
logger,
14+
logWithAnsiConsoleMarkup)
15+
{
16+
}
17+
18+
public static string Name => "NSubstitute.Analyzers";
19+
20+
public override Uri? DocumentationLink { get; set; } = new ("https://github.com/nsubstitute/NSubstitute.Analyzers/tree/master/documentation/rules", UriKind.Absolute);
21+
22+
protected override AnalyzerProviderBaseRuleData CreateData()
23+
=> new (Name);
24+
25+
protected override async Task ReCollect(
26+
AnalyzerProviderBaseRuleData data)
27+
{
28+
ArgumentNullException.ThrowIfNull(data);
29+
30+
var web = new HtmlWeb();
31+
var htmlDoc = await web.LoadFromWebAsync(DocumentationLink!.AbsoluteUri).ConfigureAwait(false);
32+
var articleNode = htmlDoc.DocumentNode.SelectNodes("//article[@class='markdown-body entry-content container-lg']").First();
33+
var articleTableRows = articleNode.SelectNodes("//*//table[1]//tr").ToList();
34+
35+
foreach (var row in articleTableRows)
36+
{
37+
if (row.SelectNodes("td") is null)
38+
{
39+
continue;
40+
}
41+
42+
var cells = row.SelectNodes("td").ToList();
43+
if (cells.Count <= 0)
44+
{
45+
continue;
46+
}
47+
48+
var aHrefNode = cells[TableColumnId].SelectSingleNode("a");
49+
if (aHrefNode is null)
50+
{
51+
continue;
52+
}
53+
54+
var code = aHrefNode.InnerText;
55+
var title = HtmlEntity.DeEntitize(cells[TableColumnTitle].InnerText);
56+
var link = "https://github.com/" + aHrefNode.Attributes["href"].Value;
57+
var category = cells[TableColumnCategory].InnerText;
58+
59+
data.Rules.Add(
60+
new Rule(
61+
code,
62+
title,
63+
link,
64+
category: category));
65+
}
66+
}
67+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
namespace Atc.CodingRules.AnalyzerProviders.Tests.Providers;
2+
3+
[Trait(Traits.Category, Traits.Categories.Integration)]
4+
[Trait(Traits.Category, Traits.Categories.SkipWhenLiveUnitTesting)]
5+
public class NSubstituteAnalyzersProviderTests
6+
{
7+
[Theory]
8+
[InlineData(ProviderCollectingMode.LocalCache)]
9+
[InlineData(ProviderCollectingMode.GitHub)]
10+
[InlineData(ProviderCollectingMode.ReCollect)]
11+
public async Task CollectBaseRules(ProviderCollectingMode providerCollectingMode)
12+
{
13+
// Arrange
14+
var provider = new NSubstituteAnalyzersProvider(NullLogger.Instance);
15+
16+
// Act
17+
var actual = await provider.CollectBaseRules(providerCollectingMode);
18+
19+
// Assert
20+
Assert.NotNull(actual);
21+
Assert.NotNull(actual.Name);
22+
Assert.Equal(NSubstituteAnalyzersProvider.Name, actual.Name);
23+
Assert.NotNull(actual.Rules);
24+
Assert.True(actual.Rules.Count >= 23);
25+
}
26+
}

0 commit comments

Comments
 (0)