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 @@ -894,6 +894,20 @@ codeunit 139940 "Qlty. Inspection Utility"
exit(QltyResultEvaluation.CheckIfValueIsString(ValueToCheck, AcceptableValue, QltyCaseSensitivity));
end;

/// <summary>
/// Wrapper for internal procedure CheckIfValueIsInPredefinedList from Qlty. Result Evaluation codeunit.
/// </summary>
/// <param name="ValueToCheck">The value to check.</param>
/// <param name="AcceptableValue">The acceptable value condition: a comma or pipe separated list of literal values. A blank value means no condition, and the default "anything except empty" tokens are also accepted.</param>
/// <param name="QltyCaseSensitivity">The case sensitivity option.</param>
/// <returns>True if the value matches one of the listed literal values, false otherwise.</returns>
internal procedure CheckIfValueIsInPredefinedList(ValueToCheck: Text; AcceptableValue: Text; QltyCaseSensitivity: Enum "Qlty. Case Sensitivity"): Boolean
var
QltyResultEvaluation: Codeunit "Qlty. Result Evaluation";
begin
exit(QltyResultEvaluation.CheckIfValueIsInPredefinedList(ValueToCheck, AcceptableValue, QltyCaseSensitivity));
end;

/// <summary>
/// Wrapper for internal procedure ValidateQltyInspectionLine from Qlty. Result Evaluation codeunit.
/// Validates an inspection line using the single-parameter internal signature.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ codeunit 20410 "Qlty. Result Evaluation"
LoopConditionMet := QltyBooleanParsing.GetBooleanFor(TestValue) = QltyBooleanParsing.GetBooleanFor(Condition)
else
LoopConditionMet := CheckIfValueIsString(TestValue, Condition, QltyCaseSensitivity);
QltyTestValueType::"Value Type Text", QltyTestValueType::"Value Type Option", QltyTestValueType::"Value Type Table Lookup", QltyTestValueType::"Value Type Text Expression":
QltyTestValueType::"Value Type Option", QltyTestValueType::"Value Type Table Lookup":
LoopConditionMet := CheckIfValueIsInPredefinedList(TestValue, Condition, QltyCaseSensitivity);
QltyTestValueType::"Value Type Text", QltyTestValueType::"Value Type Text Expression":
LoopConditionMet := CheckIfValueIsString(TestValue, Condition, QltyCaseSensitivity);
QltyTestValueType::"Value Type Date":
begin
Expand Down Expand Up @@ -700,6 +702,36 @@ codeunit 20410 "Qlty. Result Evaluation"
exit(not TempTestStringValueQltyTest.IsEmpty());
end;

internal procedure CheckIfValueIsInPredefinedList(ValueToCheck: Text; AcceptableValue: Text; QltyCaseSensitivity: Enum "Qlty. Case Sensitivity"): Boolean
var
SingleAcceptableValue: Text;
begin
// Option and Table Lookup tests use a fixed set of predefined values. Their conditions are a
// comma or pipe separated list of literal values that may contain special filter characters such
// as parentheses, so they must be compared literally instead of being interpreted as a filter.
if IsAnythingExceptEmptyCondition(AcceptableValue) then
exit(ValueToCheck <> '');

if IsBlankOrEmptyCondition(AcceptableValue) then
exit(true);

if QltyCaseSensitivity = QltyCaseSensitivity::Insensitive then begin
ValueToCheck := ValueToCheck.ToLower();
AcceptableValue := AcceptableValue.ToLower();
end;

AcceptableValue := AcceptableValue.Replace('|', ',');
foreach SingleAcceptableValue in AcceptableValue.Split(',') do begin
SingleAcceptableValue := SingleAcceptableValue.Trim();
if SingleAcceptableValue = '' then
continue;
if ValueToCheck = SingleAcceptableValue then
exit(true);
end;

exit(false);
end;

/// <summary>
/// OnBeforeEvaluateResult gives an opportunity to change how a result is evaluated.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,42 @@ codeunit 139963 "Qlty. Tests - Result Eval."
LibraryAssert.IsTrue(QltyInspectionUtility.CheckIfValueIsString('wildCardSearch', 'wild*'), 'String wildcard 2');
end;

[Test]
procedure ValueOptionWithSpecialCharacters()
var
QltyInspectionUtility: Codeunit "Qlty. Inspection Utility";
CaseOption: Enum "Qlty. Case Sensitivity";
begin
// [SCENARIO 639903] Option/Table Lookup conditions are matched literally, so predefined values containing
// special filter characters such as parentheses do not raise a filter error.

// [GIVEN] An option test with values that contain parentheses 'Test(1),Test(2)'
// [WHEN] Evaluating a selected option value against a comma separated pass condition
// [THEN] The value matches its literal option without interpreting '(' as a filter operator
LibraryAssert.IsTrue(QltyInspectionUtility.CheckIfValueIsInPredefinedList('Test(1)', 'Test(1),Test(2)', CaseOption::Sensitive), 'Option special chars comma list first');
LibraryAssert.IsTrue(QltyInspectionUtility.CheckIfValueIsInPredefinedList('Test(2)', 'Test(1),Test(2)', CaseOption::Sensitive), 'Option special chars comma list second');
LibraryAssert.IsFalse(QltyInspectionUtility.CheckIfValueIsInPredefinedList('Test(3)', 'Test(1),Test(2)', CaseOption::Sensitive), 'Option special chars not in list');

// [THEN] A trailing space after the condition list is tolerated
LibraryAssert.IsTrue(QltyInspectionUtility.CheckIfValueIsInPredefinedList('Test(2)', 'Test(1),Test(2) ', CaseOption::Sensitive), 'Option special chars trailing space');

// [THEN] Pipe separated lists are also supported
LibraryAssert.IsTrue(QltyInspectionUtility.CheckIfValueIsInPredefinedList('C', 'C|D', CaseOption::Sensitive), 'Option pipe list match');
LibraryAssert.IsFalse(QltyInspectionUtility.CheckIfValueIsInPredefinedList('A', 'C|D', CaseOption::Sensitive), 'Option pipe list no match');

// [THEN] Empty value does not match a non-empty condition and an empty condition matches anything
LibraryAssert.IsFalse(QltyInspectionUtility.CheckIfValueIsInPredefinedList('', 'C|D', CaseOption::Sensitive), 'Option empty value');
LibraryAssert.IsTrue(QltyInspectionUtility.CheckIfValueIsInPredefinedList('A', '', CaseOption::Sensitive), 'Option empty condition');

// [THEN] Empty tokens from a malformed list (trailing or doubled delimiters) do not match an empty value
LibraryAssert.IsFalse(QltyInspectionUtility.CheckIfValueIsInPredefinedList('', 'A,', CaseOption::Sensitive), 'Option empty token trailing delimiter');
LibraryAssert.IsFalse(QltyInspectionUtility.CheckIfValueIsInPredefinedList('', 'A||B', CaseOption::Sensitive), 'Option empty token doubled delimiter');
LibraryAssert.IsTrue(QltyInspectionUtility.CheckIfValueIsInPredefinedList('B', 'A||B', CaseOption::Sensitive), 'Option doubled delimiter still matches real value');

// [THEN] Case insensitive comparison matches values that differ only by case
LibraryAssert.IsTrue(QltyInspectionUtility.CheckIfValueIsInPredefinedList('test(1)', 'Test(1),Test(2)', CaseOption::Insensitive), 'Option special chars case insensitive');
end;

[TryFunction]
procedure Try_TestValueDateIntentionallyBad()
var
Expand Down
Loading