Skip to content

Commit a6efccb

Browse files
authored
Allow to define a custom StringComparsion for Equals Operator (#3048)
* Add string comparison enhancements to ContentFilter. - Introduce static `EqualsOperatorDefaultStringComparison` Property in the `ContentFilter` class for customizable string comparison. - Update `IsEqual` method in the `Utils` class to accept an optional `StringComparison` parameter. * Add Test * fix default stringComparsion Operator to be Ordinal * Remove obsolete DBNull check * Add Comment
1 parent 2a7de7d commit a6efccb

File tree

3 files changed

+43
-7
lines changed

3 files changed

+43
-7
lines changed

Stack/Opc.Ua.Core/Stack/Types/ContentFilter.Evaluate.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ namespace Opc.Ua
2424
/// </summary>
2525
public partial class ContentFilter
2626
{
27+
#region Public Static Properties
28+
/// <summary>
29+
/// Set the default StringComparison to use when evaluating the Equals operator.
30+
/// This property is meant to be set as a config setting and not set / reset on a per context basis, to ensure consistency
31+
/// </summary>
32+
public static StringComparison EqualsOperatorDefaultStringComparison { get; set; } = StringComparison.Ordinal;
33+
#endregion
34+
2735
#region Public functions
2836
/// <summary>
2937
/// Evaluates the first element in the ContentFilter. If the first or any
@@ -407,14 +415,19 @@ private static bool IsEqual(object value1, object value2)
407415
return value1 == null && value2 == null;
408416
}
409417

410-
if (value1 is DBNull || value2 is DBNull)
418+
if (value1.GetType() != value2.GetType())
411419
{
412-
return value1 is DBNull && value2 is DBNull;
420+
return false;
413421
}
414422

415-
if (value1.GetType() != value2.GetType())
423+
//check for strings
424+
if (value1 is string string1)
416425
{
417-
return false;
426+
if (value2 is not string string2)
427+
{
428+
return false;
429+
}
430+
return string1.Equals(string2, EqualsOperatorDefaultStringComparison);
418431
}
419432

420433
return Utils.IsEqual(value1, value2);

Stack/Opc.Ua.Core/Types/Utils/Utils.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2631,7 +2631,7 @@ public static void UpdateExtension<T>(ref XmlElementCollection extensions, XmlQu
26312631
extensions.Add(document.DocumentElement);
26322632
}
26332633
}
2634-
#endregion
2634+
#endregion
26352635

26362636
#region Reflection Helper Functions
26372637
/// <summary>
@@ -2985,7 +2985,7 @@ public static bool ValidateNonce(byte[] nonce, MessageSecurityMode securityMode,
29852985
[Obsolete("Use equivalent method from the Opc.Ua.Nonce class")]
29862986
public static bool ValidateNonce(byte[] nonce, MessageSecurityMode securityMode, uint minNonceLength)
29872987
{
2988-
return NewNonceImplementation.ValidateNonce(nonce,securityMode, minNonceLength);
2988+
return NewNonceImplementation.ValidateNonce(nonce, securityMode, minNonceLength);
29892989
}
29902990
}
29912991

@@ -3248,6 +3248,6 @@ public static bool IsRunningOnMono()
32483248
{
32493249
return s_isRunningOnMonoValue.Value;
32503250
}
3251-
#endregion
3251+
#endregion
32523252
}
32533253
}

Tests/Opc.Ua.Core.Tests/Types/ContentFilter/ContentFilterTests.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,29 @@ public void NonBoolWithBinary(object operandFirst1, object operandFirst2, Filter
312312
Assert.AreEqual(expectedResult, result);
313313
}
314314

315+
[Test]
316+
[TestCase("mainstation", "mainstation", StringComparison.Ordinal, true)]
317+
[TestCase("mainstation", "Mainstation", StringComparison.Ordinal, false)]
318+
[TestCase("mainstation", "Mainstation", StringComparison.OrdinalIgnoreCase, true)]
319+
[TestCase("mainstation", "Mainstation", StringComparison.InvariantCultureIgnoreCase, true)]
320+
[TestCase("mainstation", "Mainstation", StringComparison.InvariantCulture, false)]
321+
[TestCase("mainstation", "mainstation", StringComparison.InvariantCulture, true)]
322+
public void EqualsStringComparsion(string operandFirst1, string operandFirst2, StringComparison stringComparison, object expectedResult)
323+
{
324+
Opc.Ua.ContentFilter.EqualsOperatorDefaultStringComparison = stringComparison;
325+
LiteralOperand loperand1 = new LiteralOperand { Value = new Variant(operandFirst1)};
326+
LiteralOperand loperand2 = new LiteralOperand { Value = new Variant(operandFirst2)};
327+
328+
ContentFilterElement filterElement = new ContentFilterElement();
329+
filterElement.FilterOperator = FilterOperator.Equals;
330+
filterElement.SetOperands(new List<LiteralOperand>() { loperand1, loperand2 });
331+
Filter.WhereClause.Elements = new[] { filterElement };
332+
333+
// apply filter.
334+
object result = Filter.WhereClause.Evaluate(FilterContext, TestFilterTarget);
335+
Assert.AreEqual(expectedResult, result);
336+
}
337+
315338

316339
#endregion
317340
}

0 commit comments

Comments
 (0)