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
@@ -0,0 +1,13 @@
table 50100 "My Table"
{
fields
{
field(1; "Test Option"; [|Option|])
{
Caption = 'Test Option';
DataClassification = CustomerContent;
OptionCaption = '0,1,2,3,4,5';
OptionMembers = "0","1","2","3","4","5";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
codeunit 50100 MyCodeunit
{
var
[|Mode|]: Option "None","Allow deletion",Match;

procedure MyProcedure()
var
ReservationManagement: Codeunit "Reservation Management PTE";
begin
ReservationManagement.SetItemTrackingHandling(Mode);
end;
}

codeunit 50101 "Reservation Management PTE"
{
procedure SetItemTrackingHandling(Mode: Option "None","Allow deletion",Match)
begin
end;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
codeunit 50100 MyCodeunit
{
procedure MyProcedure()
var
ReservationManagement: Codeunit "Reservation Management PTE";
[|Mode|]: Option "None","Allow deletion",Match;
begin
ReservationManagement.SetItemTrackingHandling(Mode);
end;
}

codeunit 50101 "Reservation Management PTE"
{
procedure SetItemTrackingHandling(Mode: Option "None","Allow deletion",Match)
begin
end;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
codeunit 50100 MyCodeunit
{
procedure MyProcedure() Mode: [|Option "None","Allow deletion",Match|]
begin

end;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
codeunit 50100 MyCodeunit
{
procedure MyProcedure([|TestOption: Option " ","Test1","Test2"|])
begin
case TestOption of
TestOption::" ":
exit;
TestOption::"Test1":
Message('test 1');
TestOption::"Test2":
Message('test 2');
end;
end;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
table 50100 "Dataverse Project PTE"
{
ExternalName = 'prefix_project';
TableType = CDS;
Description = '';
Caption = 'Project';

fields
{
field(1; prefix_projectId; Guid)
{
ExternalName = 'prefix_projectid';
ExternalType = 'Uniqueidentifier';
ExternalAccess = Insert;
Description = 'Unique identifier for entity instances';
Caption = 'Project';
}
field(2; prefix_name; Text[100])
{
ExternalName = 'prefix_name';
ExternalType = 'String';
Description = 'The name of the custom entity.';
Caption = 'Name';
}
field(25; statecode; [|Option|])
{
ExternalName = 'statecode';
ExternalType = 'State';
ExternalAccess = Modify;
Description = 'Status of the Project';
Caption = 'Status';
InitValue = " ";
OptionMembers = " ",Active,Inactive;
OptionOrdinalValues = -1, 0, 1;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
codeunit 50100 MyCodeunit
{
trigger OnRun()
var
OptionVariable: Option "", "test1";
begin
OnCodeunitRun(OptionVariable);
end;

[IntegrationEvent(false, false)]
local procedure OnCodeunitRun(var OptionVariable: Option "", "test1")
begin
end;
}

codeunit 50101 MySubscriber
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::MyCodeunit, OnCodeunitRun, '', false, false)]
local procedure OnCodeunitRun_MyCodeunit(var [|OptionVariable: Option "", "test1"|])
begin

end;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
table 50100 MyTable
{
fields
{
field(1; "No."; Code[20]) { }
field(2; "Warehouse Status"; [|Option|])
{
CalcFormula = min("My Warehouse Shipment Header"."Document Status" where("No." = field("No.")));
FieldClass = FlowField;
OptionMembers = " ","Partially Picked","Partially Shipped","Completely Picked","Completely Shipped";
}
}
}

table 50101 "My Warehouse Shipment Header"
{
fields
{
field(1; "No."; Code[20]) { }
field(2; "Document Status"; Option)
{
OptionMembers = " ","Partially Picked","Partially Shipped","Completely Picked","Completely Shipped";
}
}
}

enum 50100 "Warehouse Status" { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
table 50100 "My Table"
{
fields
{
field(1; MyField; Integer)
{
DataClassification = ToBeClassified;
}
field(2; "Test Option"; [|Option|])
{
Caption = 'Test Option';
ObsoleteState = Pending;
DataClassification = CustomerContent;
OptionCaption = '0,1,2,3,4,5';
OptionMembers = "0","1","2","3","4","5";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//TODO: Test with an codeunit from a dependency extension so the ."GetLocation().IsInSource" returns false
codeunit 50100 MyCodeunit
{
var
ModeGlobal: Option "None","Allow deletion",Match; // Should not raise a diagnostic

procedure MyProcedure()
var
ReservationManagement: Codeunit "Reservation Management";
ModeLocal: Option "None","Allow deletion",Match; // Should not raise a diagnostic
begin
ReservationManagement.SetItemTrackingHandling(ModeLocal);
ReservationManagement.SetItemTrackingHandling(ModeGlobal);
end;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using RoslynTestKit;

namespace ALCops.LinterCop.Test
{
public class OptionTypeShouldBeEnum : NavCodeAnalysisBase
{
private AnalyzerTestFixture _fixture;
private string _testCasePath;

[SetUp]
public void Setup()
{
_fixture = RoslynFixtureFactory.Create<Analyzers.OptionTypeShouldBeEnum>();

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

[Test]
[TestCase("OptionField")]
[TestCase("OptionParameterGlobalVar")]
[TestCase("OptionParameterLocalVar")]
[TestCase("OptionReturnValue")]
[TestCase("OptionVariable")]
public async Task HasDiagnostic(string testCase)
{
var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(HasDiagnostic), $"{testCase}.al"))
.ConfigureAwait(false);

_fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.OptionTypeShouldBeEnum);
}

[Test]
[TestCase("CDSDocument")]
[TestCase("EventSubscriberOption")]
[TestCase("FlowField")]
[TestCase("ObsoleteFieldOption")]
// [TestCase("OptionParameter")] //TODO: See remarks in the test file
public async Task NoDiagnostic(string testCase)
{
var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(NoDiagnostic), $"{testCase}.al"))
.ConfigureAwait(false);

_fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.OptionTypeShouldBeEnum);
}
}
}
27 changes: 27 additions & 0 deletions src/ALCops.LinterCop/ALCops.LinterCopAnalyzers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,33 @@ internal static string ObjectIdInDeclarationTitle {
}
}

/// <summary>
/// Looks up a localized string similar to Enums are preferred over Option types because they provide stronger typing, better extensibility, and clearer intent. Using Enums reduces error-prone patterns commonly associated with Option fields and improves maintainability and versioning of AL code..
/// </summary>
internal static string OptionTypeShouldBeEnumDescription {
get {
return ResourceManager.GetString("OptionTypeShouldBeEnumDescription", resourceCulture);
}
}

/// <summary>
/// Looks up a localized string similar to Prefer using an Enum instead of an Option type..
/// </summary>
internal static string OptionTypeShouldBeEnumMessageFormat {
get {
return ResourceManager.GetString("OptionTypeShouldBeEnumMessageFormat", resourceCulture);
}
}

/// <summary>
/// Looks up a localized string similar to Prefer Enum over Option type.
/// </summary>
internal static string OptionTypeShouldBeEnumTitle {
get {
return ResourceManager.GetString("OptionTypeShouldBeEnumTitle", resourceCulture);
}
}

/// <summary>
/// Looks up a localized string similar to Adopting the use of the new PageStyle datatype allows to more easily get the supported pagestyles via IntelliSense and avoids incorrect behaviour when a typo is made in hardcoded strings or label variables..
/// </summary>
Expand Down
9 changes: 9 additions & 0 deletions src/ALCops.LinterCop/ALCops.LinterCopAnalyzers.resx
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,15 @@
<data name="ObjectIdInDeclarationActionTitle" xml:space="preserve">
<value>ALCops: Replace id with name of object reference</value>
</data>
<data name="OptionTypeShouldBeEnumTitle" xml:space="preserve">
<value>Prefer Enum over Option type</value>
</data>
<data name="OptionTypeShouldBeEnumMessageFormat" xml:space="preserve">
<value>Prefer using an Enum instead of an Option type.</value>
</data>
<data name="OptionTypeShouldBeEnumDescription" xml:space="preserve">
<value>Enums are preferred over Option types because they provide stronger typing, better extensibility, and clearer intent. Using Enums reduces error-prone patterns commonly associated with Option fields and improves maintainability and versioning of AL code.</value>
</data>
<data name="PageStyleStringLiteralTitle" xml:space="preserve">
<value>Use the new PageStyle datatype instead string literals</value>
</data>
Expand Down
Loading
Loading