Skip to content

Commit

Permalink
Added BitwiseAnd and BitwiseOr filter operators and unit tests for ex…
Browse files Browse the repository at this point in the history
…isting filter operators (#1633)

* Added BitwiseAnd and BitwiseOr filter operators

* Added positive unit tests for filter operators; Changed Cast BitwiseAnd and BitwiseOr operators to return boolean values or null

* BitwiseAnd and BitwiseOr return the operation value; Improved unit tests

* Added missing handling of BitwiseAnd and BitwiseOr filter operators under the ContentFilterElement.Validate and ContentFilterElement.ToString methods

* Changed Cast operator to return value instead of bool; Fixed typos and adapted unit tests
  • Loading branch information
mrsuciu committed Jan 20, 2022
1 parent cf95cb9 commit 5451149
Show file tree
Hide file tree
Showing 3 changed files with 471 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Stack/Opc.Ua.Core/Stack/Nodes/ContentFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,8 @@ public virtual ContentFilter.ElementResult Validate(FilterContext context, int i
case FilterOperator.LessThanOrEqual:
case FilterOperator.Like:
case FilterOperator.Cast:
case FilterOperator.BitwiseAnd:
case FilterOperator.BitwiseOr:
{
operandCount = 2;
break;
Expand Down Expand Up @@ -740,6 +742,8 @@ public virtual string ToString(INodeTable nodeTable)
case FilterOperator.LessThanOrEqual:
case FilterOperator.Like:
case FilterOperator.Or:
case FilterOperator.BitwiseAnd:
case FilterOperator.BitwiseOr:
{
buffer.AppendFormat("'{1}' {0} '{2}'", FilterOperator, operand1, operand2);
break;
Expand Down
150 changes: 150 additions & 0 deletions Stack/Opc.Ua.Core/Stack/Types/ContentFilter.Evaluate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ private object Evaluate(FilterContext context, IFilterTarget target, int index)
{
return RelatedTo(context, target, element);
}

case FilterOperator.BitwiseAnd:
{
return BitwiseAnd(context, target, element);
}

case FilterOperator.BitwiseOr:
{
return BitwiseOr(context, target, element);
}
}

throw new ServiceResultException(StatusCodes.BadUnexpectedError, "FilterOperator is not recognized.");
Expand Down Expand Up @@ -183,6 +193,31 @@ private FilterOperand[] GetOperands(ContentFilterElement element, int expectedCo
return operands;
}

/// <summary>
/// Returns the operands necessary for the BitwiseAnd and BitwiseOr operations
/// </summary>
private Tuple<object, object> GetBitwiseOperands(FilterContext context, IFilterTarget target, ContentFilterElement element)
{
FilterOperand[] operands = GetOperands(element, 2);

object lhs = GetValue(context, operands[0], target);
object rhs = GetValue(context, operands[1], target);

if (lhs == null || rhs == null)
{
return Tuple.Create<object, object>(null, null);
}

if (!isIntegerType(GetBuiltInType(lhs)) || !isIntegerType(GetBuiltInType(rhs)))
{
return Tuple.Create<object, object>(null, null);
}

DoImplicitConversion(ref lhs, ref rhs);

return Tuple.Create(lhs, rhs);
}

/// <summary>
/// Returns the value for the element.
/// </summary>
Expand Down Expand Up @@ -422,6 +457,23 @@ private static bool Match(string target, string pattern)

return Regex.IsMatch(target, expression);
}

/// <summary>
/// Returns true if the type is Integer, otherwise returns false
/// </summary>
/// <param name="aType">The type to check against</param>
/// <returns>true if the type is Integer, otherwise returns false</returns>
private static bool isIntegerType(BuiltInType aType)
{
if (aType == BuiltInType.Byte || aType == BuiltInType.SByte ||
aType == BuiltInType.Int16 || aType == BuiltInType.UInt16 ||
aType == BuiltInType.Int32 || aType == BuiltInType.UInt32 ||
aType == BuiltInType.Int64 || aType == BuiltInType.UInt64)
{
return true;
}
return false;
}
#endregion

#region Casting
Expand Down Expand Up @@ -1509,6 +1561,8 @@ private static object Cast(object source, BuiltInType sourceType, BuiltInType ta
// conversion not supported.
return null;
}


#endregion

#region FilterOperator Implementations
Expand Down Expand Up @@ -2109,6 +2163,102 @@ private bool RelatedTo(FilterContext context, IFilterTarget target, ContentFilte
return false;
}
}

/// <summary>
/// BitwiseAnd FilterOperator
/// </summary>
private object BitwiseAnd(FilterContext context, IFilterTarget target, ContentFilterElement element)
{
(object lhs, object rhs) = GetBitwiseOperands(context, target, element);
if (lhs == null || rhs == null)
{
return null;
}

Type systemType = lhs.GetType();
if (systemType == typeof(byte))
{
return (byte)lhs & (byte)rhs;
}
if (systemType == typeof(sbyte))
{
return (sbyte)lhs & (sbyte)rhs;
}
if (systemType == typeof(short))
{
return (short)lhs & (short)rhs;
}
if (systemType == typeof(ushort))
{
return (ushort)lhs & (ushort)rhs;
}
if (systemType == typeof(int))
{
return (int)lhs & (int)rhs;
}
if (systemType == typeof(uint))
{
return (uint)lhs & (uint)rhs;
}
if (systemType == typeof(long))
{
return (long)lhs & (long)rhs;
}
if (systemType == typeof(ulong))
{
return (ulong)lhs & (ulong)rhs;
}
return null;
}

/// <summary>
/// BitwiseOr FilterOperator
/// </summary>
private object BitwiseOr(FilterContext context, IFilterTarget target, ContentFilterElement element)
{
(object lhs, object rhs) = GetBitwiseOperands(context, target, element);
if (lhs == null || rhs == null)
{
return null;
}

Type systemType = lhs.GetType();
if (systemType == typeof(byte))
{
return (byte)lhs | (byte)rhs;
}
if (systemType == typeof(sbyte))
{
return (sbyte)lhs | (sbyte)rhs;
}
if (systemType == typeof(short))
{
return (short)lhs | (short)rhs;
}
if (systemType == typeof(ushort))
{
return (ushort)lhs | (ushort)rhs;
}
if (systemType == typeof(int))
{
return (int)lhs | (int)rhs;
}
if (systemType == typeof(uint))
{
return (uint)lhs | (uint)rhs;
}
if (systemType == typeof(long))
{
return (long)lhs | (long)rhs;
}
if (systemType == typeof(ulong))
{
return (ulong)lhs | (ulong)rhs;
}
return null;
}


#endregion
}
}

0 comments on commit 5451149

Please sign in to comment.