Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Uses `RegisterCompilationStartAction` to discover which tables are referenced by

## Test coverage

Tests are commented out (TODO: `WithRuleSetPath` in RoslynTestKit needed since rule is `isEnabledByDefault: false`).
The rule is `isEnabledByDefault: false`, so the test class enables it via a co-located `FieldGroupsRequired.ruleset.json` fixture passed through `AnalyzerTestFixtureConfig.RuleSetPath` (requires RoslynTestKit that applies the ruleset to the compilation).

**HasDiagnostic (3 cases, commented out):** BrickIsMissing, DropDownIsMissing, TemporaryTable (referenced by page).
**HasDiagnostic (3 cases):** BrickIsMissing, DropDownIsMissing, TemporaryTable (referenced by page).
**NoDiagnostic (2 cases):** HasBrickAndDropDown, TemporaryTable (no page reference).
34 changes: 34 additions & 0 deletions .github/instructions/testing.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,40 @@ public async Task NoDiagnosticWithTargetOnPrem(string testCase)

This requires `using Microsoft.Dynamics.Nav.CodeAnalysis;` for `CompilationOptions` and `CompilationTarget`.

## Testing rules that are `isEnabledByDefault: false`

Rules declared with `isEnabledByDefault: false` never run in tests unless a ruleset explicitly enables them. Inject a co-located ruleset JSON fixture via `AnalyzerTestFixtureConfig.RuleSetPath` (requires RoslynTestKit 1.4.0+, which loads the ruleset and applies it to the compilation's diagnostic options).

Add a `{RuleName}.ruleset.json` next to the test class in its `Rules/{RuleName}/` folder:

```json
{
"name": "Enable AC0013",
"description": "Enables AC0013 for tests.",
"rules": [ { "id": "AC0013", "action": "Info" } ]
}
```

Set `action` to the rule's default severity (`Info`, `Warning`, etc.) to enable it. Then wire it in `Setup` (compute `_testCasePath` **before** creating the fixture, since the path feeds `RuleSetPath`):

```csharp
[SetUp]
public void Setup()
{
_testCasePath = Path.Combine(
Directory.GetParent(Environment.CurrentDirectory)!.Parent!.Parent!.FullName,
Path.Combine("Rules", nameof(MyRule)));

_fixture = RoslynFixtureFactory.Create<Analyzers.MyRule>(
new AnalyzerTestFixtureConfig
{
RuleSetPath = Path.Combine(_testCasePath, $"{nameof(MyRule)}.ruleset.json")
});
}
```

The ruleset JSON resolves via the same source-tree absolute path as the `.al` fixtures, so no `CopyToOutputDirectory` is required. For code-fix tests, pass `RuleSetPath` on `CodeFixTestFixtureConfig` too.

## Naming Conventions

| Element | Convention | Example |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@

<!-- RoslynTestKit -->
<ItemGroup Condition="'$(IsLegacyNavTfm)'!='true'">
<PackageReference Include="ALCops.RoslynTestKit" Version="1.3.0" />
<PackageReference Include="ALCops.RoslynTestKit" Version="1.4.0" />
</ItemGroup>

<!-- On legacy NAV TFMs, suppress package assets and directly reference the netstandard2.1 DLL -->
<ItemGroup Condition="'$(IsLegacyNavTfm)'=='true'">
<PackageReference Include="ALCops.RoslynTestKit" Version="1.3.0" ExcludeAssets="all" IncludeAssets="none" GeneratePathProperty="true" />
<PackageReference Include="ALCops.RoslynTestKit" Version="1.4.0" ExcludeAssets="all" IncludeAssets="none" GeneratePathProperty="true" />
<Reference Include="$(PkgALCops_RoslynTestKit)/lib/netstandard2.1/RoslynTestKit.dll">
<Private>True</Private>
</Reference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,29 @@ public class FieldGroupsRequired : NavCodeAnalysisBase
[SetUp]
public void Setup()
{
_fixture = RoslynFixtureFactory.Create<Analyzers.FieldGroupsRequired>();

_testCasePath = Path.Combine(
Directory.GetParent(
Environment.CurrentDirectory)!.Parent!.Parent!.FullName,
Path.Combine("Rules", nameof(FieldGroupsRequired)));

_fixture = RoslynFixtureFactory.Create<Analyzers.FieldGroupsRequired>(
new AnalyzerTestFixtureConfig
{
RuleSetPath = Path.Combine(_testCasePath, $"{nameof(FieldGroupsRequired)}.ruleset.json")
});
}

//TODO: Expose .WithRuleSetPath in RoslynTestKit, so we can enable/disable diagnostics in tests
// [Test]
// [TestCase("BrickIsMissing")]
// [TestCase("DropDownIsMissing")]
// [TestCase("TemporaryTable")]
// public async Task HasDiagnostic(string testCase)
// {
// var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(HasDiagnostic), $"{testCase}.al"))
// .ConfigureAwait(false);
[Test]
[TestCase("BrickIsMissing")]
[TestCase("DropDownIsMissing")]
[TestCase("TemporaryTable")]
public async Task HasDiagnostic(string testCase)
{
var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(HasDiagnostic), $"{testCase}.al"))
.ConfigureAwait(false);

// _fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.FieldGroupsRequired);
// }
_fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.FieldGroupsRequired);
}

[Test]
[TestCase("HasBrickAndDropDown")]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Enable AC0013",
"description": "Enables the default-disabled FieldGroupsRequired rule so it can be tested.",
"rules": [
{
"id": "AC0013",
"action": "Info"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,36 @@ public class LabelLockedMustHaveTokSuffix : NavCodeAnalysisBase
[SetUp]
public void Setup()
{
_fixture = RoslynFixtureFactory.Create<Analyzers.LabelTokLockedConvention>();

_testCasePath = Path.Combine(
Directory.GetParent(
Environment.CurrentDirectory)!.Parent!.Parent!.FullName,
Path.Combine("Rules", nameof(LabelLockedMustHaveTokSuffix)));

_fixture = RoslynFixtureFactory.Create<Analyzers.LabelTokLockedConvention>(
new AnalyzerTestFixtureConfig
{
RuleSetPath = Path.Combine(_testCasePath, $"{nameof(LabelLockedMustHaveTokSuffix)}.ruleset.json")
});
}

//TODO: Expose .WithRuleSetPath in RoslynTestKit, so we can enable/disable diagnostics in tests
// [Test]
// [TestCase("Label")]
// public async Task HasDiagnostic(string testCase)
// {
// var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(HasDiagnostic), $"{testCase}.al"))
// .ConfigureAwait(false);
[Test]
[TestCase("Label")]
public async Task HasDiagnostic(string testCase)
{
var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(HasDiagnostic), $"{testCase}.al"))
.ConfigureAwait(false);

// _fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.LabelLockedMustHaveTokSuffix);
// }
_fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.LabelLockedMustHaveTokSuffix);
}

// [Test]
// [TestCase("Label")]
// public async Task NoDiagnostic(string testCase)
// {
// var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(NoDiagnostic), $"{testCase}.al"))
// .ConfigureAwait(false);
[Test]
[TestCase("Label")]
public async Task NoDiagnostic(string testCase)
{
var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(NoDiagnostic), $"{testCase}.al"))
.ConfigureAwait(false);

// _fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.LabelLockedMustHaveTokSuffix);
// }
_fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.LabelLockedMustHaveTokSuffix);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Enable AC0021",
"description": "Enables the default-disabled LabelLockedMustHaveTokSuffix rule so it can be tested.",
"rules": [
{
"id": "AC0021",
"action": "Info"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,37 @@ public class TableDataPerCompanyDeclaration : NavCodeAnalysisBase
[SetUp]
public void Setup()
{
_fixture = RoslynFixtureFactory.Create<Analyzers.TableDataPerCompanyDeclaration>();

_testCasePath = Path.Combine(
Directory.GetParent(
Environment.CurrentDirectory)!.Parent!.Parent!.FullName,
Path.Combine("Rules", nameof(TableDataPerCompanyDeclaration)));

_fixture = RoslynFixtureFactory.Create<Analyzers.TableDataPerCompanyDeclaration>(
new AnalyzerTestFixtureConfig
{
RuleSetPath = Path.Combine(_testCasePath, $"{nameof(TableDataPerCompanyDeclaration)}.ruleset.json")
});
}

//TODO: Expose .WithRuleSetPath in RoslynTestKit, so we can enable/disable diagnostics in tests
// [Test]
// [TestCase("DataPerCompanyPropertyMissing")]
// public async Task HasDiagnostic(string testCase)
// {
// var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(HasDiagnostic), $"{testCase}.al"))
// .ConfigureAwait(false);
[Test]
[TestCase("DataPerCompanyPropertyMissing")]
public async Task HasDiagnostic(string testCase)
{
var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(HasDiagnostic), $"{testCase}.al"))
.ConfigureAwait(false);

// _fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.TableDataPerCompanyDeclaration);
// }
_fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.TableDataPerCompanyDeclaration);
}

// [Test]
// [TestCase("DataPerCompanyFalse")]
// [TestCase("DataPerCompanyTrue")]
// public async Task NoDiagnostic(string testCase)
// {
// var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(NoDiagnostic), $"{testCase}.al"))
// .ConfigureAwait(false);
[Test]
[TestCase("DataPerCompanyFalse")]
[TestCase("DataPerCompanyTrue")]
public async Task NoDiagnostic(string testCase)
{
var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(NoDiagnostic), $"{testCase}.al"))
.ConfigureAwait(false);

// _fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.TableDataPerCompanyDeclaration);
// }
_fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.TableDataPerCompanyDeclaration);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Enable AC0008",
"description": "Enables the default-disabled TableDataPerCompanyDeclaration rule so it can be tested.",
"rules": [
{
"id": "AC0008",
"action": "Info"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@

<!-- RoslynTestKit -->
<ItemGroup Condition="'$(IsLegacyNavTfm)'!='true'">
<PackageReference Include="ALCops.RoslynTestKit" Version="1.3.0" />
<PackageReference Include="ALCops.RoslynTestKit" Version="1.4.0" />
</ItemGroup>

<!-- On legacy NAV TFMs, suppress package assets and directly reference the netstandard2.1 DLL -->
<ItemGroup Condition="'$(IsLegacyNavTfm)'=='true'">
<PackageReference Include="ALCops.RoslynTestKit" Version="1.1.1"
<PackageReference Include="ALCops.RoslynTestKit" Version="1.4.0"
ExcludeAssets="all"
IncludeAssets="none"
GeneratePathProperty="true" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@

<!-- RoslynTestKit -->
<ItemGroup Condition="'$(IsLegacyNavTfm)'!='true'">
<PackageReference Include="ALCops.RoslynTestKit" Version="1.3.0" />
<PackageReference Include="ALCops.RoslynTestKit" Version="1.4.0" />
</ItemGroup>

<!-- On legacy NAV TFMs, suppress package assets and directly reference the netstandard2.1 DLL -->
<ItemGroup Condition="'$(IsLegacyNavTfm)'=='true'">
<PackageReference Include="ALCops.RoslynTestKit" Version="1.1.1"
<PackageReference Include="ALCops.RoslynTestKit" Version="1.4.0"
ExcludeAssets="all"
IncludeAssets="none"
GeneratePathProperty="true" />
Expand Down
4 changes: 2 additions & 2 deletions src/ALCops.LinterCop.Test/ALCops.LinterCop.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@

<!-- RoslynTestKit -->
<ItemGroup Condition="'$(IsLegacyNavTfm)'!='true'">
<PackageReference Include="ALCops.RoslynTestKit" Version="1.3.0" />
<PackageReference Include="ALCops.RoslynTestKit" Version="1.4.0" />
</ItemGroup>

<!-- On legacy NAV TFMs, suppress package assets and directly reference the netstandard2.1 DLL -->
<ItemGroup Condition="'$(IsLegacyNavTfm)'=='true'">
<PackageReference Include="ALCops.RoslynTestKit" Version="1.1.1"
<PackageReference Include="ALCops.RoslynTestKit" Version="1.4.0"
ExcludeAssets="all"
IncludeAssets="none"
GeneratePathProperty="true" />
Expand Down
4 changes: 2 additions & 2 deletions src/ALCops.PlatformCop.Test/ALCops.PlatformCop.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@

<!-- RoslynTestKit -->
<ItemGroup Condition="'$(IsLegacyNavTfm)'!='true'">
<PackageReference Include="ALCops.RoslynTestKit" Version="1.3.0" />
<PackageReference Include="ALCops.RoslynTestKit" Version="1.4.0" />
</ItemGroup>

<!-- On legacy NAV TFMs, suppress package assets and directly reference the netstandard2.1 DLL -->
<ItemGroup Condition="'$(IsLegacyNavTfm)'=='true'">
<PackageReference Include="ALCops.RoslynTestKit" Version="1.1.1"
<PackageReference Include="ALCops.RoslynTestKit" Version="1.4.0"
ExcludeAssets="all"
IncludeAssets="none"
GeneratePathProperty="true" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,37 @@ public class AccessPropertyExplicitlySet : NavCodeAnalysisBase
[SetUp]
public void Setup()
{
_fixture = RoslynFixtureFactory.Create<Analyzers.AccessPropertyExplicitlySet>();

_testCasePath = Path.Combine(
Directory.GetParent(
Environment.CurrentDirectory)!.Parent!.Parent!.FullName,
Path.Combine("Rules", nameof(AccessPropertyExplicitlySet)));

_fixture = RoslynFixtureFactory.Create<Analyzers.AccessPropertyExplicitlySet>(
new AnalyzerTestFixtureConfig
{
RuleSetPath = Path.Combine(_testCasePath, $"{nameof(AccessPropertyExplicitlySet)}.ruleset.json")
});
}

//TODO: Expose .WithRuleSetPath in RoslynTestKit, so we can enable/disable diagnostics in tests
// [Test]
// [TestCase("CodeunitObject")]
// public async Task HasDiagnostic(string testCase)
// {
// var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(HasDiagnostic), $"{testCase}.al"))
// .ConfigureAwait(false);
[Test]
[TestCase("CodeunitObject")]
public async Task HasDiagnostic(string testCase)
{
var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(HasDiagnostic), $"{testCase}.al"))
.ConfigureAwait(false);

// _fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.AccessPropertyExplicitlySet);
// }
_fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.AccessPropertyExplicitlySet);
}

// [Test]
// [TestCase("CodeunitObject")]
// [TestCase("TableFieldWithoutAccess")]
// public async Task NoDiagnostic(string testCase)
// {
// var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(NoDiagnostic), $"{testCase}.al"))
// .ConfigureAwait(false);
[Test]
[TestCase("CodeunitObject")]
[TestCase("TableFieldWithoutAccess")]
public async Task NoDiagnostic(string testCase)
{
var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(NoDiagnostic), $"{testCase}.al"))
.ConfigureAwait(false);

// _fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.AccessPropertyExplicitlySet);
// }
_fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.AccessPropertyExplicitlySet);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Enable PC0006",
"description": "Enables the default-disabled AccessPropertyExplicitlySet rule so it can be tested.",
"rules": [
{
"id": "PC0006",
"action": "Warning"
}
]
}
Loading