Example #1
0
        public void AddFunctionResolveWorksTest()
        {
            const string function = "add";
            const EvaluationMode evaluationMode = EvaluationMode.Resolve;

            #region 1L + 1L
            var parameters1 = new ArrayList {1L, 1L};
            var expressionFunction1 = new ExpressionFunction(function, parameters1, evaluationMode);
            Assert.IsNotNull(expressionFunction1);

            var result1 = expressionFunction1.Run();

            Assert.IsNotNull(result1);
            Assert.IsInstanceOfType(result1, typeof(long));
            Assert.AreEqual(2L, result1);
            #endregion

            #region 10L + 10L
            var parameters2 = new ArrayList { 10L, 10L };
            var expressionFunction2 = new ExpressionFunction(function, parameters2, evaluationMode);
            Assert.IsNotNull(expressionFunction2);

            var result2 = expressionFunction2.Run();

            Assert.IsNotNull(result2);
            Assert.IsInstanceOfType(result2, typeof(long));
            Assert.AreEqual(20L, result2);
            #endregion
        }
Example #2
0
        public void AddFunctionResolveCharInvalidInputFormatTest()
        {
            const string function = "add";
            const EvaluationMode evaluationMode = EvaluationMode.Resolve;

            #region 1 char + 1 char
            var parameters1 = new ArrayList { '1', '1' };
            var expresssionFunction1 = new ExpressionFunction(function, parameters1, evaluationMode);
            expresssionFunction1.Run();
            #endregion
        }
Example #3
0
        public void AddFunctionResolveStringInvalidInputFormatTest()
        {
            const string function = "add";
            const EvaluationMode evaluationMode = EvaluationMode.Resolve;

            #region 10 string + 10 string
            var parameters1 = new ArrayList { "10", "10" };
            var expresssionFunction1 = new ExpressionFunction(function, parameters1, evaluationMode);
            expresssionFunction1.Run();
            #endregion
        }
        /// <summary>
        /// Evaluates the function.
        /// </summary>
        /// <param name="function">The function.</param>
        /// <param name="mode">The mode.</param>
        /// <returns>The result of the evaluated function.</returns>
        private object EvaluateFunction(string function, EvaluationMode mode)
        {
            Logger.Instance.WriteMethodEntry(EventIdentifier.ExpressionEvaluatorEvaluateFunction, "Function: '{0}'. Evaluation Mode: '{1}'.", function, mode);

            object result = null;
            try
            {
                // Locate the opening and closing () characters for the function
                // by looking for the first and last instance of each character
                // This will ignore any nested functions which may be used as a parameter
                int open = function.IndexOf('(');
                int close = function.LastIndexOf(')');

                // Break apart the function expression to identify the function name
                // and parameter string (content between parentheses)
                string functionName = function.Substring(0, open);
                string parameterString = function.Substring(open + 1, close - open - 1);

                // Create new array lists to hold the unresolved and resolved parameters for the function
                // Only evaluate parameters if the parameter string is not empty, as it will
                // be for functions like DateTimeNow() and Null()
                ArrayList unresolvedParameters = new ArrayList();
                ArrayList parameters = new ArrayList();
                if (!string.IsNullOrEmpty(parameterString.Trim()))
                {
                    // The function expression could contain nested functions with their own commas
                    // For example, Trim(Left(ReplaceString(attribute, "This", "That"), 8))
                    // Consequently, we can't assume that a split by comma returns each parameter
                    // We need to loop through each and determine if a parameter needs to be reassembled
                    // based on the positioning of ( and ) characters and quotation marks
                    StringBuilder reassembled = new StringBuilder();
                    bool openString = false;
                    int openFunctions = 0;

                    // First, make sure that there are an appropriate number of ( and ) characters
                    // and also make sure there is no open string in the function
                    foreach (char c in parameterString)
                    {
                        if (c.Equals('\"'))
                        {
                            openString = !openString;
                        }

                        if (c.Equals('(') && !openString)
                        {
                            openFunctions += 1;
                        }

                        if (c.Equals(')') && !openString)
                        {
                            openFunctions -= 1;
                        }
                    }

                    // If there is an open string or the number of open and close 
                    // parantheses characters do not match, throw an exception
                    if (openString)
                    {
                        throw Logger.Instance.ReportError(EventIdentifier.ExpressionEvaluatorEvaluateFunctionQuotesValidationError, new InvalidFunctionFormatException(Messages.ExpressionEvaluator_FunctionParameterQuotesValidationError, functionName));
                    }

                    if (openFunctions != 0)
                    {
                        throw Logger.Instance.ReportError(EventIdentifier.ExpressionEvaluatorEvaluateFunctionParenthesisValidationError, new InvalidFunctionFormatException(Messages.ExpressionEvaluator_FunctionParameterParenthesisValidationError, functionName));
                    }

                    // Loop through each parameter fragment, split by comma,
                    // and determine if reassembly is required
                    foreach (string s in parameterString.Split(','))
                    {
                        // Count the number of ( and ) characters in the current string
                        // Only consider the parentheses relevent if it is not in an open string
                        foreach (char c in s)
                        {
                            if (c.Equals('\"'))
                            {
                                openString = !openString;
                            }
                            else if (c.Equals('(') && !openString)
                            {
                                openFunctions += 1;
                            }
                            else if (c.Equals(')') && !openString)
                            {
                                openFunctions -= 1;
                            }
                        }

                        // Add the string to the reassembled string builder
                        // and determine how to proceed based on whether or not
                        // we are currently reassembling parameter fragments
                        reassembled.Append(s);
                        if (openFunctions > 0 || openString)
                        {
                            reassembled.Append(",");
                        }
                        else
                        {
                            // If a parameter is not open, it either means that no
                            // reassembly was required or we have completed reassembly
                            // Either way, add the parameter to the list of unresolved parameters
                            // and reset the string builder
                            unresolvedParameters.Add(reassembled.ToString().Trim());
                            reassembled = new StringBuilder();
                        }
                    }

                    foreach (string s in unresolvedParameters)
                    {
                        Logger.Instance.WriteVerbose(EventIdentifier.ExpressionEvaluatorEvaluateFunction, "Resolving unresolved function parameter '{0}'.", s);

                        ParameterType type = DetermineParameterType(s);

                        switch (type)
                        {
                            case ParameterType.String:
                                // Add the string value after trimming the quotes
                                parameters.Add(EscapeString(s));
                                break;
                            case ParameterType.Integer:
                                // Add the parsed value as long as FIM datatype is System.Int64
                                parameters.Add(long.Parse(s, CultureInfo.InvariantCulture));
                                break;
                            case ParameterType.Boolean:
                                // Add the parsed Boolean value
                                parameters.Add(bool.Parse(s));
                                break;
                            case ParameterType.Lookup:
                                if (mode == EvaluationMode.Parse)
                                {
                                    // For parse, add the lookup to the cache 
                                    // Mark the grammar in the parameter list by adding the appropriate enum value
                                    if (!this.lookupCache.ContainsKey(s))
                                    {
                                        this.lookupCache.Add(s, null);
                                    }

                                    parameters.Add(ParameterType.Lookup);
                                }
                                else
                                {
                                    // For resolution, pull the value from the lookup cache and
                                    // add it to the parameter list
                                    if (this.lookupCache.ContainsKey(s))
                                    {
                                        parameters.Add(this.lookupCache[s]);
                                    }
                                    else
                                    {
                                        throw Logger.Instance.ReportError(EventIdentifier.ExpressionEvaluatorEvaluateFunctionLookupCacheValidationError, new InvalidFunctionFormatException(Messages.ExpressionEvaluator_LookupCacheValidationError, s));
                                    }
                                }

                                break;
                            case ParameterType.Variable:
                                if (mode == EvaluationMode.Parse)
                                {
                                    // For parse, add the variable to the cache 
                                    // Mark the variable in the parameter list by adding the appropriate enum value
                                    if (!this.variableCache.ContainsKey(s))
                                    {
                                        this.variableCache.Add(s, null);
                                    }

                                    parameters.Add(ParameterType.Variable);
                                }
                                else
                                {
                                    // For resolution, pull the value from the variable cache and
                                    // add it to the parameter list
                                    if (this.variableCache.ContainsKey(s))
                                    {
                                        parameters.Add(this.variableCache[s]);
                                    }
                                    else
                                    {
                                        throw Logger.Instance.ReportError(EventIdentifier.ExpressionEvaluatorEvaluateFunctionVariableCacheValidationError, new InvalidFunctionFormatException(Messages.ExpressionEvaluator_VariableCacheValidationError, s));
                                    }
                                }

                                break;
                            case ParameterType.Function:
                                if (mode == EvaluationMode.Parse)
                                {
                                    // For parse, recursively evaluate the function and any nested functions
                                    // Mark the function in the parameter list by adding the appropriate enum value
                                    this.EvaluateFunction(s, mode);
                                    parameters.Add(ParameterType.Function);
                                }
                                else
                                {
                                    // For resolution, recursively resolve the function and any nested functions
                                    // and add the end result to the parameter list for the current function
                                    parameters.Add(this.EvaluateFunction(s, mode));
                                }

                                break;
                            case ParameterType.Expression:

                                if (mode == EvaluationMode.Parse)
                                {
                                    // For parse, recursively evaluate the expression and any nested functions
                                    // Mark the expression in the paramter list by adding the appropriate enum value
                                    this.EvaluateExpression(s, mode);
                                    parameters.Add(ParameterType.Expression);
                                }
                                else
                                {
                                    // For resolution, recursively resolve the expression and any nested functions
                                    // and add the end result to the parameter list for the current function
                                    parameters.Add(this.EvaluateExpression(s, mode));
                                }

                                break;
                            default:
                                throw Logger.Instance.ReportError(EventIdentifier.ExpressionEvaluatorEvaluateFunctionParameterTypeValidationError, new InvalidFunctionFormatException());
                        }
                    }
                }

                // Special handling for EvaluateExpression() function so that the lookups in the expression to evaluate are resolved
                // Assumption: the lookups used in the expression are already used in some other expressions
                // e.g. Consider [//Query/Site/xUserTemplateExpression] returning IIF(Eq([//Target/Department],"HR"),"Template1","Template2")
                // We want EvaluateExpression([//Query/Site/xUserTemplateExpression]). 
                // In this case caller activity need to ensure that [//Target/Department] is already used any other expression
                // so that it's part of LookupCache.
                if (functionName.Equals(ParameterType.EvaluateExpression.ToString(), StringComparison.OrdinalIgnoreCase))
                {
                    Logger.Instance.WriteWarning(EventIdentifier.ExpressionEvaluatorEvaluateFunctionDeprecatedFunctionWarning, Messages.ExpressionFunction_DeprecatedFunctionWarning, ParameterType.EvaluateExpression.ToString(), "Resolve Dynamic Grammar capability of UpdateResources activity");

                    string expression = this.EvaluateExpression(parameterString, mode) as string; // so e.g. IIF(Eq([//Target/Department],"HR"),"Template1","Template2")
                    if (mode != EvaluationMode.Parse && !string.IsNullOrEmpty(expression))
                    {
                        // now evalaute the actual expression i.e. e.g. IIF(Eq([//Target/Department],"HR"),"Template1","Template2")
                        result = this.EvaluateExpression(expression, mode);
                    }
                }
                else
                {
                    // Evaluate the function to make sure it is properly formatted,
                    // all required parameters are available, and parameters are of the appropriate type
                    // For most functions, the root value is allowed to be null to handle 
                    // scenarios when an attribute or expression is resolved to null
                    // In this circumstance, an exception should not be thrown but the function should resolve to null
                    ExpressionFunction expressionFunction = new ExpressionFunction(functionName, parameters, mode);
                    result = expressionFunction.Run();
                }

                return result;
            }
            finally
            {
                Logger.Instance.WriteMethodExit(EventIdentifier.ExpressionEvaluatorEvaluateFunction, "Function: '{0}'. Evaluation Mode: '{1}'. Returning: '{2}'.", function, mode, result);
            }
        }