From 4e36b979f57c3ab77f977bcb34b2989d215b1b66 Mon Sep 17 00:00:00 2001 From: Dusan Jakovljevic <134404137+JakovljevicDusan@users.noreply.github.com> Date: Thu, 21 May 2026 23:31:30 +0200 Subject: [PATCH 1/3] Fix --- .../Result/QltyResultEvaluation.Codeunit.al | 93 +++++++++++++++++++ .../Template/Test/QltyTest.Table.al | 13 +++ 2 files changed, 106 insertions(+) diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al index b8a5c1d869..98a75867a0 100644 --- a/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al +++ b/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al @@ -22,6 +22,7 @@ codeunit 20410 "Qlty. Result Evaluation" IsDefaultTextTok: Label '<>''''', Locked = true; InvalidDataTypeErr: Label 'The value "%1" is not allowed for %2, it is not a %3.', Comment = '%1=the value, %2=field name,%3=field type.'; NotInAllowableValuesErr: Label 'The value "%1" is not allowed for %2, it must be in the range of "%3".', Comment = '%1=the value, %2=field name,%3=field type.'; + InvalidAllowableValuesFormatErr: Label 'The allowable values "%1" are not a valid filter expression for %2 of type %3.', Comment = '%1=the allowable values, %2=field name, %3=field type.'; trigger OnRun() var @@ -324,6 +325,98 @@ codeunit 20410 "Qlty. Result Evaluation" ValidateAllowableValuesOnText(TestNameForError, QltyTest."Default Value", QltyTest."Allowable Values", QltyTest."Test Value Type", TempBufferQltyTestLookupValue, QltyCaseSensitivity); end; + /// + /// Validates that the allowable values expression is a valid filter for the given test value type. + /// + /// The test whose allowable values expression should be validated. + internal procedure ValidateAllowableValuesFormat(var QltyTest: Record "Qlty. Test") + var + TestNameForError: Text; + begin + if QltyTest.Description <> '' then + TestNameForError := QltyTest.Description + else + TestNameForError := QltyTest.Code; + + ValidateAllowableValuesFormat(TestNameForError, QltyTest."Allowable Values", QltyTest."Test Value Type"); + end; + + /// + /// Validates that the allowable values expression is a valid filter for the given test value type. + /// + /// Friendly identifier used in error messages. + /// The allowable values filter expression to validate. + /// The test value type that the filter expression must match. + local procedure ValidateAllowableValuesFormat(NumberOrNameOfTestNameForError: Text; AllowableValues: Text; QltyTestValueType: Enum "Qlty. Test Value Type") + var + IsValid: Boolean; + begin + if AllowableValues = '' then + exit; + + if IsBlankOrEmptyCondition(AllowableValues) then + exit; + + if IsAnythingExceptEmptyCondition(AllowableValues) then + exit; + + // Allowable values may contain inline expressions like [Field] that are resolved at evaluation time. + // Defer validation until resolution. + if AllowableValues.Contains('[') then + exit; + + IsValid := true; + case QltyTestValueType of + QltyTestValueType::"Value Type Decimal": + IsValid := TryApplyDecimalFilter(AllowableValues); + QltyTestValueType::"Value Type Integer": + IsValid := TryApplyIntegerFilter(AllowableValues); + QltyTestValueType::"Value Type Date": + IsValid := TryApplyDateFilter(AllowableValues); + QltyTestValueType::"Value Type DateTime": + IsValid := TryApplyDateTimeFilter(AllowableValues); + end; + + if not IsValid then + Error(InvalidAllowableValuesFormatErr, AllowableValues, NumberOrNameOfTestNameForError, QltyTestValueType); + end; + + [TryFunction] + local procedure TryApplyDecimalFilter(FilterExpression: Text) + var + TempQltyInspectionLine: Record "Qlty. Inspection Line" temporary; + begin + TempQltyInspectionLine.SetFilter("Derived Numeric Value", FilterExpression); + if TempQltyInspectionLine.IsEmpty() then; + end; + + [TryFunction] + local procedure TryApplyIntegerFilter(FilterExpression: Text) + var + TempInteger: Record "Integer" temporary; + begin + TempInteger.SetFilter(Number, FilterExpression); + if TempInteger.IsEmpty() then; + end; + + [TryFunction] + local procedure TryApplyDateFilter(FilterExpression: Text) + var + TempDateLookupBuffer: Record "Date Lookup Buffer" temporary; + begin + TempDateLookupBuffer.SetFilter("Period Start", FilterExpression); + if TempDateLookupBuffer.IsEmpty() then; + end; + + [TryFunction] + local procedure TryApplyDateTimeFilter(FilterExpression: Text) + var + TempQltyInspectionHeader: Record "Qlty. Inspection Header" temporary; + begin + TempQltyInspectionHeader.SetFilter("Finished Date", FilterExpression); + if TempQltyInspectionHeader.IsEmpty() then; + end; + local procedure ValidateAllowableValuesOnText(NumberOrNameOfTestNameForError: Text; var TextToValidate: Text[250]; AllowableValues: Text; QltyTestValueType: Enum "Qlty. Test Value Type"; var TempBufferQltyTestLookupValue: Record "Qlty. Test Lookup Value" temporary; QltyCaseSensitivity: Enum "Qlty. Case Sensitivity") var QltyBooleanParsing: Codeunit "Qlty. Boolean Parsing"; diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al index 9f4cbf3006..66e4c203fc 100644 --- a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al +++ b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al @@ -54,8 +54,11 @@ table 20401 "Qlty. Test" { Caption = 'Allowable Values'; ToolTip = 'Specifies an expression for the range of values you can enter or select for the Test. Depending on the Test Value Type, the expression format varies. For example if you want a measurement such as a percentage that collects between 0 and 100 you would enter 0..100. This is not the pass or acceptable condition, these are just the technically possible values that the inspector can enter. You would then enter a passing condition in your result conditions. If you had a result of Pass being 80 to 100, you would then configure 80..100 for that result.'; + trigger OnValidate() begin + Rec.ValidateAllowableValuesFormat(); + if Rec."Test Value Type" in [Rec."Test Value Type"::"Value Type Option", Rec."Test Value Type"::"Value Type Table Lookup"] then Rec."Allowable Values" := CopyStr(Rec."Allowable Values".Replace(', ', ','), 1, MaxStrLen(Rec."Allowable Values")); end; @@ -472,6 +475,16 @@ table 20401 "Qlty. Test" QltyResultEvaluation.ValidateAllowableValuesOnTest(Rec); end; + /// + /// Validates that the allowable values expression is a valid filter for the test value type. + /// + procedure ValidateAllowableValuesFormat() + var + QltyResultEvaluation: Codeunit "Qlty. Result Evaluation"; + begin + QltyResultEvaluation.ValidateAllowableValuesFormat(Rec); + end; + /// /// Code = the unique code /// Description = raw description. From afff4e84a2f5a8e1482cf2ca624418f5376c2612 Mon Sep 17 00:00:00 2001 From: Dusan Jakovljevic <134404137+JakovljevicDusan@users.noreply.github.com> Date: Fri, 22 May 2026 18:53:06 +0200 Subject: [PATCH 2/3] Support "Value Type Boolean" and add tests --- .../Result/QltyResultEvaluation.Codeunit.al | 16 +- .../test/src/QltyTestsResultEval.Codeunit.al | 434 ++++++++++++++++++ 2 files changed, 448 insertions(+), 2 deletions(-) diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al index 98a75867a0..cedd3e29ce 100644 --- a/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al +++ b/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al @@ -371,6 +371,8 @@ codeunit 20410 "Qlty. Result Evaluation" IsValid := TryApplyDecimalFilter(AllowableValues); QltyTestValueType::"Value Type Integer": IsValid := TryApplyIntegerFilter(AllowableValues); + QltyTestValueType::"Value Type Boolean": + IsValid := TryApplyBooleanFilter(AllowableValues); QltyTestValueType::"Value Type Date": IsValid := TryApplyDateFilter(AllowableValues); QltyTestValueType::"Value Type DateTime": @@ -399,6 +401,16 @@ codeunit 20410 "Qlty. Result Evaluation" if TempInteger.IsEmpty() then; end; + [TryFunction] + local procedure TryApplyBooleanFilter(FilterExpression: Text) + var + QltyBooleanParsing: Codeunit "Qlty. Boolean Parsing"; + begin + // Valid boolean allowable values are: Yes, No, True, False, 1, 0, On, Off (and variations) + if not QltyBooleanParsing.CanTextBeInterpretedAsBooleanIsh(FilterExpression) then + Error(''); + end; + [TryFunction] local procedure TryApplyDateFilter(FilterExpression: Text) var @@ -486,9 +498,8 @@ codeunit 20410 "Qlty. Result Evaluation" if not (IsBlankOrEmptyCondition(AllowableValues) and (TextToValidate = '')) then if not QltyResultEvaluation.CheckIfValueIsString(TextToValidate, ConvertStr(AllowableValues, ',', '|'), QltyCaseSensitivity) then Error(NotInAllowableValuesErr, TextToValidate, NumberOrNameOfTestNameForError, AllowableValues); - QltyTestValueType::"Value Type Option", - QltyTestValueType::"Value Type Table Lookup": + QltyTestValueType::"Value Type Table Lookup": begin TextToValidate := CopyStr(TextToValidate.Trim(), 1, MaxStrLen(TextToValidate)); @@ -512,6 +523,7 @@ codeunit 20410 "Qlty. Result Evaluation" Error(NotInAllowableValuesErr, TextToValidate, NumberOrNameOfTestNameForError, AllowableValues); end; end; + OnAfterValidateAllowableValuesOnText(NumberOrNameOfTestNameForError, TextToValidate, AllowableValues, QltyTestValueType, TempBufferQltyTestLookupValue, QltyCaseSensitivity); end; diff --git a/src/Apps/W1/Quality Management/test/src/QltyTestsResultEval.Codeunit.al b/src/Apps/W1/Quality Management/test/src/QltyTestsResultEval.Codeunit.al index 91159fca6e..05f7d8a17a 100644 --- a/src/Apps/W1/Quality Management/test/src/QltyTestsResultEval.Codeunit.al +++ b/src/Apps/W1/Quality Management/test/src/QltyTestsResultEval.Codeunit.al @@ -2071,6 +2071,440 @@ codeunit 139963 "Qlty. Tests - Result Eval." LibraryAssert.ExpectedError(StrSubstNo(Expected4Err, OptionListQltyInspectionLine."Test Code")); end; + [Test] + procedure ValidateAllowableValuesFormat_Decimal_ValidFormats() + var + DecimalQltyTest: Record "Qlty. Test"; + begin + // [SCENARIO] Validate that ValidateAllowableValuesFormat accepts valid decimal filter expressions + + // [GIVEN] A quality test with decimal type is created + DecimalQltyTest.Init(); + DecimalQltyTest.Code := 'TESTDEC'; + DecimalQltyTest.Description := 'Test Decimal'; + DecimalQltyTest."Test Value Type" := DecimalQltyTest."Test Value Type"::"Value Type Decimal"; + DecimalQltyTest.Insert(); + + // [WHEN] Allowable values are set to range expression "0..100" + DecimalQltyTest."Allowable Values" := '0..100'; + // [THEN] ValidateAllowableValuesFormat passes without error + DecimalQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to greater than expression ">0" + DecimalQltyTest."Allowable Values" := '>0'; + // [THEN] ValidateAllowableValuesFormat passes without error + DecimalQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to less than or equal expression "<=50" + DecimalQltyTest."Allowable Values" := '<=50'; + // [THEN] ValidateAllowableValuesFormat passes without error + DecimalQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to exact value "25.5" + DecimalQltyTest."Allowable Values" := '25.5'; + // [THEN] ValidateAllowableValuesFormat passes without error + DecimalQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to list of values "10|20|30" + DecimalQltyTest."Allowable Values" := '10|20|30'; + // [THEN] ValidateAllowableValuesFormat passes without error + DecimalQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are blank + DecimalQltyTest."Allowable Values" := ''; + // [THEN] ValidateAllowableValuesFormat passes without error + DecimalQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values contain expression with brackets "[Field]" + DecimalQltyTest."Allowable Values" := '0..[Field]'; + // [THEN] ValidateAllowableValuesFormat is deferred and passes without error + DecimalQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to not empty condition "<>''" + DecimalQltyTest."Allowable Values" := '<>'''''; + // [THEN] ValidateAllowableValuesFormat passes without error + DecimalQltyTest.ValidateAllowableValuesFormat(); + end; + + [Test] + procedure ValidateAllowableValuesFormat_Decimal_InvalidFormats() + var + DecimalQltyTest: Record "Qlty. Test"; + begin + // [SCENARIO] Validate that ValidateAllowableValuesFormat rejects invalid decimal filter expressions + + // [GIVEN] A quality test with decimal type is created + DecimalQltyTest.Init(); + DecimalQltyTest.Code := 'TESTDEC2'; + DecimalQltyTest.Description := 'Test Decimal Invalid'; + DecimalQltyTest."Test Value Type" := DecimalQltyTest."Test Value Type"::"Value Type Decimal"; + DecimalQltyTest.Insert(); + + // [WHEN] Allowable values are set to invalid text "not a number" + DecimalQltyTest."Allowable Values" := 'not a number'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror DecimalQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to invalid operator "==5" + DecimalQltyTest."Allowable Values" := '==5'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror DecimalQltyTest.ValidateAllowableValuesFormat(); + end; + + [Test] + procedure ValidateAllowableValuesFormat_Integer_ValidFormats() + var + IntegerQltyTest: Record "Qlty. Test"; + begin + // [SCENARIO] Validate that ValidateAllowableValuesFormat accepts valid integer filter expressions + + // [GIVEN] A quality test with integer type is created + IntegerQltyTest.Init(); + IntegerQltyTest.Code := 'TESTINT'; + IntegerQltyTest.Description := 'Test Integer'; + IntegerQltyTest."Test Value Type" := IntegerQltyTest."Test Value Type"::"Value Type Integer"; + IntegerQltyTest.Insert(); + + // [WHEN] Allowable values are set to range expression "0..100" + IntegerQltyTest."Allowable Values" := '0..100'; + // [THEN] ValidateAllowableValuesFormat passes without error + IntegerQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to greater than expression ">0" + IntegerQltyTest."Allowable Values" := '>0'; + // [THEN] ValidateAllowableValuesFormat passes without error + IntegerQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to less than or equal expression "<=50" + IntegerQltyTest."Allowable Values" := '<=50'; + // [THEN] ValidateAllowableValuesFormat passes without error + IntegerQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to exact value "25" + IntegerQltyTest."Allowable Values" := '25'; + // [THEN] ValidateAllowableValuesFormat passes without error + IntegerQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to list of values "1|2|3|4|5" + IntegerQltyTest."Allowable Values" := '1|2|3|4|5'; + // [THEN] ValidateAllowableValuesFormat passes without error + IntegerQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are blank + IntegerQltyTest."Allowable Values" := ''; + // [THEN] ValidateAllowableValuesFormat passes without error + IntegerQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values contain expression with brackets "[Field]" + IntegerQltyTest."Allowable Values" := '1..[Field]'; + // [THEN] ValidateAllowableValuesFormat is deferred and passes without error + IntegerQltyTest.ValidateAllowableValuesFormat(); + end; + + [Test] + procedure ValidateAllowableValuesFormat_Integer_InvalidFormats() + var + IntegerQltyTest: Record "Qlty. Test"; + begin + // [SCENARIO] Validate that ValidateAllowableValuesFormat rejects invalid integer filter expressions + + // [GIVEN] A quality test with integer type is created + IntegerQltyTest.Init(); + IntegerQltyTest.Code := 'TESTINT2'; + IntegerQltyTest.Description := 'Test Integer Invalid'; + IntegerQltyTest."Test Value Type" := IntegerQltyTest."Test Value Type"::"Value Type Integer"; + IntegerQltyTest.Insert(); + + // [WHEN] Allowable values are set to decimal value "1.5" + IntegerQltyTest."Allowable Values" := '1.5'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror IntegerQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to invalid text "not an integer" + IntegerQltyTest."Allowable Values" := 'not an integer'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror IntegerQltyTest.ValidateAllowableValuesFormat(); + end; + + [Test] + procedure ValidateAllowableValuesFormat_Date_ValidFormats() + var + DateQltyTest: Record "Qlty. Test"; + begin + // [SCENARIO] Validate that ValidateAllowableValuesFormat accepts valid date filter expressions + + // [GIVEN] A quality test with date type is created + DateQltyTest.Init(); + DateQltyTest.Code := 'TESTDATE'; + DateQltyTest.Description := 'Test Date'; + DateQltyTest."Test Value Type" := DateQltyTest."Test Value Type"::"Value Type Date"; + DateQltyTest.Insert(); + + // [WHEN] Allowable values are set to exact date "2024-01-01" + DateQltyTest."Allowable Values" := '2024-01-01'; + // [THEN] ValidateAllowableValuesFormat passes without error + DateQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to date range "2024-01-01..2024-12-31" + DateQltyTest."Allowable Values" := '2024-01-01..2024-12-31'; + // [THEN] ValidateAllowableValuesFormat passes without error + DateQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to greater than date ">2024-01-01" + DateQltyTest."Allowable Values" := '>2024-01-01'; + // [THEN] ValidateAllowableValuesFormat passes without error + DateQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are blank + DateQltyTest."Allowable Values" := ''; + // [THEN] ValidateAllowableValuesFormat passes without error + DateQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values contain expression with brackets "[Field]" + DateQltyTest."Allowable Values" := '>[Field]'; + // [THEN] ValidateAllowableValuesFormat is deferred and passes without error + DateQltyTest.ValidateAllowableValuesFormat(); + end; + + [Test] + procedure ValidateAllowableValuesFormat_Date_InvalidFormats() + var + DateQltyTest: Record "Qlty. Test"; + begin + // [SCENARIO] Validate that ValidateAllowableValuesFormat rejects invalid date filter expressions + + // [GIVEN] A quality test with date type is created + DateQltyTest.Init(); + DateQltyTest.Code := 'TESTDATE2'; + DateQltyTest.Description := 'Test Date Invalid'; + DateQltyTest."Test Value Type" := DateQltyTest."Test Value Type"::"Value Type Date"; + DateQltyTest.Insert(); + + // [WHEN] Allowable values are set to invalid date "99/99/9999" + DateQltyTest."Allowable Values" := '99/99/9999'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror DateQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to invalid text "not a date" + DateQltyTest."Allowable Values" := 'not a date'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror DateQltyTest.ValidateAllowableValuesFormat(); + end; + + [Test] + procedure ValidateAllowableValuesFormat_DateTime_ValidFormats() + var + DateTimeQltyTest: Record "Qlty. Test"; + begin + // [SCENARIO] Validate that ValidateAllowableValuesFormat accepts valid datetime filter expressions + + // [GIVEN] A quality test with datetime type is created + DateTimeQltyTest.Init(); + DateTimeQltyTest.Code := 'TESTDT'; + DateTimeQltyTest.Description := 'Test DateTime'; + DateTimeQltyTest."Test Value Type" := DateTimeQltyTest."Test Value Type"::"Value Type DateTime"; + DateTimeQltyTest.Insert(); + + // [WHEN] Allowable values are set to exact datetime "2024-01-01 10:30:00" + DateTimeQltyTest."Allowable Values" := '2024-01-01 10:30:00'; + // [THEN] ValidateAllowableValuesFormat passes without error + DateTimeQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to datetime range "2024-01-01 00:00:00..2024-12-31 23:59:59" + DateTimeQltyTest."Allowable Values" := '2024-01-01 00:00:00..2024-12-31 23:59:59'; + // [THEN] ValidateAllowableValuesFormat passes without error + DateTimeQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to greater than datetime ">2024-01-01 10:00:00" + DateTimeQltyTest."Allowable Values" := '>2024-01-01 10:00:00'; + // [THEN] ValidateAllowableValuesFormat passes without error + DateTimeQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are blank + DateTimeQltyTest."Allowable Values" := ''; + // [THEN] ValidateAllowableValuesFormat passes without error + DateTimeQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values contain expression with brackets "[Field]" + DateTimeQltyTest."Allowable Values" := '<[Field]'; + // [THEN] ValidateAllowableValuesFormat is deferred and passes without error + DateTimeQltyTest.ValidateAllowableValuesFormat(); + end; + + [Test] + procedure ValidateAllowableValuesFormat_DateTime_InvalidFormats() + var + DateTimeQltyTest: Record "Qlty. Test"; + begin + // [SCENARIO] Validate that ValidateAllowableValuesFormat rejects invalid datetime filter expressions + + // [GIVEN] A quality test with datetime type is created + DateTimeQltyTest.Init(); + DateTimeQltyTest.Code := 'TESTDT2'; + DateTimeQltyTest.Description := 'Test DateTime Invalid'; + DateTimeQltyTest."Test Value Type" := DateTimeQltyTest."Test Value Type"::"Value Type DateTime"; + DateTimeQltyTest.Insert(); + + // [WHEN] Allowable values are set to invalid datetime "99/99/9999 99:99:99" + DateTimeQltyTest."Allowable Values" := '99/99/9999 99:99:99'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror DateTimeQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to invalid text "not a datetime" + DateTimeQltyTest."Allowable Values" := 'not a datetime'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror DateTimeQltyTest.ValidateAllowableValuesFormat(); + end; + + [Test] + procedure ValidateAllowableValuesFormat_Boolean_ValidFormats() + var + BooleanQltyTest: Record "Qlty. Test"; + begin + // [SCENARIO] Validate that ValidateAllowableValuesFormat accepts valid boolean values + + // [GIVEN] A quality test with boolean type is created + BooleanQltyTest.Init(); + BooleanQltyTest.Code := 'TESTBOOL'; + BooleanQltyTest.Description := 'Test Boolean'; + BooleanQltyTest."Test Value Type" := BooleanQltyTest."Test Value Type"::"Value Type Boolean"; + BooleanQltyTest.Insert(); + + // [WHEN] Allowable values are set to "Yes" + BooleanQltyTest."Allowable Values" := 'Yes'; + // [THEN] ValidateAllowableValuesFormat passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to "No" + BooleanQltyTest."Allowable Values" := 'No'; + // [THEN] ValidateAllowableValuesFormat passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to "True" + BooleanQltyTest."Allowable Values" := 'True'; + // [THEN] ValidateAllowableValuesFormat passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to "False" + BooleanQltyTest."Allowable Values" := 'False'; + // [THEN] ValidateAllowableValuesFormat passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to "1" + BooleanQltyTest."Allowable Values" := '1'; + // [THEN] ValidateAllowableValuesFormat passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to "0" + BooleanQltyTest."Allowable Values" := '0'; + // [THEN] ValidateAllowableValuesFormat passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to "On" + BooleanQltyTest."Allowable Values" := 'On'; + // [THEN] ValidateAllowableValuesFormat passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to "Off" + BooleanQltyTest."Allowable Values" := 'Off'; + // [THEN] ValidateAllowableValuesFormat passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to single-letter "Y" + BooleanQltyTest."Allowable Values" := 'Y'; + // [THEN] ValidateAllowableValuesFormat passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to single-letter "N" + BooleanQltyTest."Allowable Values" := 'N'; + // [THEN] ValidateAllowableValuesFormat passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are blank + BooleanQltyTest."Allowable Values" := ''; + // [THEN] ValidateAllowableValuesFormat passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values contain expression with brackets "[Field]" + BooleanQltyTest."Allowable Values" := '[Field]'; + // [THEN] ValidateAllowableValuesFormat is deferred and passes without error + BooleanQltyTest.ValidateAllowableValuesFormat(); + end; + + [Test] + procedure ValidateAllowableValuesFormat_Boolean_InvalidFormats() + var + BooleanQltyTest: Record "Qlty. Test"; + begin + // [SCENARIO] Validate that ValidateAllowableValuesFormat rejects invalid boolean values + + // [GIVEN] A quality test with boolean type is created + BooleanQltyTest.Init(); + BooleanQltyTest.Code := 'TESTBOOL2'; + BooleanQltyTest.Description := 'Test Boolean Invalid'; + BooleanQltyTest."Test Value Type" := BooleanQltyTest."Test Value Type"::"Value Type Boolean"; + BooleanQltyTest.Insert(); + + // [WHEN] Allowable values are set to invalid text "Maybe" + BooleanQltyTest."Allowable Values" := 'Maybe'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to invalid number "2" + BooleanQltyTest."Allowable Values" := '2'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to invalid text "not a boolean" + BooleanQltyTest."Allowable Values" := 'not a boolean'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror BooleanQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to invalid text "abc" + BooleanQltyTest."Allowable Values" := 'abc'; + // [THEN] ValidateAllowableValuesFormat raises an error + asserterror BooleanQltyTest.ValidateAllowableValuesFormat(); + end; + + [Test] + procedure ValidateAllowableValuesFormat_NonValidatedTypes() + var + TextQltyTest: Record "Qlty. Test"; + OptionQltyTest: Record "Qlty. Test"; + begin + // [SCENARIO] Validate that ValidateAllowableValuesFormat does not validate non-numeric/non-date types + + // [GIVEN] A quality test with text type is created + TextQltyTest.Init(); + TextQltyTest.Code := 'TESTTEXT'; + TextQltyTest.Description := 'Test Text'; + TextQltyTest."Test Value Type" := TextQltyTest."Test Value Type"::"Value Type Text"; + TextQltyTest.Insert(); + + // [WHEN] Allowable values are set to any text value "A|B|C" + TextQltyTest."Allowable Values" := 'A|B|C'; + // [THEN] ValidateAllowableValuesFormat passes without error (no validation for text type) + TextQltyTest.ValidateAllowableValuesFormat(); + + // [WHEN] Allowable values are set to any arbitrary text + TextQltyTest."Allowable Values" := 'any text value'; + // [THEN] ValidateAllowableValuesFormat passes without error + TextQltyTest.ValidateAllowableValuesFormat(); + + // [GIVEN] A quality test with option type is created + OptionQltyTest.Init(); + OptionQltyTest.Code := 'TESTOPT'; + OptionQltyTest.Description := 'Test Option'; + OptionQltyTest."Test Value Type" := OptionQltyTest."Test Value Type"::"Value Type Option"; + OptionQltyTest.Insert(); + + // [WHEN] Allowable values are set to comma-separated options "Option1,Option2,Option3" + OptionQltyTest."Allowable Values" := 'Option1,Option2,Option3'; + // [THEN] ValidateAllowableValuesFormat passes without error (no validation for option type) + OptionQltyTest.ValidateAllowableValuesFormat(); + end; + + local procedure GetTemplateLineConfigFilters(var QltyInspectionTemplateLine: Record "Qlty. Inspection Template Line"; var OutTemplateLineQltyIResultConditConf: Record "Qlty. I. Result Condit. Conf.") begin OutTemplateLineQltyIResultConditConf.SetRange("Condition Type", OutTemplateLineQltyIResultConditConf."Condition Type"::Template); From 3abebdf726d0571b51fb9c95d3270a3d67c6c46e Mon Sep 17 00:00:00 2001 From: Dusan Jakovljevic <134404137+JakovljevicDusan@users.noreply.github.com> Date: Fri, 22 May 2026 19:33:26 +0200 Subject: [PATCH 3/3] Code review suggestion --- .../src/Configuration/Result/QltyResultEvaluation.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al index cedd3e29ce..c1b2942c55 100644 --- a/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al +++ b/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al @@ -408,7 +408,7 @@ codeunit 20410 "Qlty. Result Evaluation" begin // Valid boolean allowable values are: Yes, No, True, False, 1, 0, On, Off (and variations) if not QltyBooleanParsing.CanTextBeInterpretedAsBooleanIsh(FilterExpression) then - Error(''); + Error(InvalidAllowableValuesFormatErr, FilterExpression, '', 'Boolean'); end; [TryFunction]