Beispiel #1
0
        /// <summary>
        /// Compares collection object with the expected value.
        /// </summary>
        /// <param name="expected">Expected value.</param>
        /// <param name="actual">Actual value.</param>
        /// <param name="path">The path to the compared object (for debugging purposes).</param>
        /// <param name="shouldThrow">Should exception be thrown if error is encountered.</param>
        /// <returns>Result of the comparison, Success or Failure.</returns>
        protected ComparisonResult CompareCollection(QueryCollectionValue expected, object actual, string path, bool shouldThrow)
        {
            this.AddToLogBuffer("Verifying collection value. Path: {0}", path);

            if (actual == null)
            {
                if (expected.IsNull)
                {
                    return(ComparisonResult.Success);
                }

                this.ThrowOrLogError(shouldThrow, "Expecting non-null value: {0} in '{1}'. Got null instead.", expected, path);

                return(ComparisonResult.Failure);
            }

            IEnumerable actualCollection = actual as IEnumerable;

            if (expected.IsNull)
            {
                return(this.ProcessExpectedNullCollection(actual, actualCollection, path, shouldThrow));
            }

            if (actualCollection == null)
            {
                this.ThrowOrLogError(shouldThrow, "Expecting a collection in '{0}'.", path);

                return(ComparisonResult.Failure);
            }

            List <object> actualElements = actualCollection.Cast <object>().ToList();

            if (expected.Elements.Count() != actualElements.Count)
            {
                this.ThrowOrLogError(shouldThrow, "Collection element counts do not match in '{0}'. Expected: {1}. Actual: {2}.", path, expected.Elements.Count(), actualElements.Count);

                return(ComparisonResult.Failure);
            }

            if (expected.IsSorted)
            {
                // for sorted collection, compare until first error is found
                for (int i = 0; i < expected.Elements.Count(); i++)
                {
                    this.Compare(expected.Elements[i], actualElements[i], path + "[" + i + "]", true);
                }
            }
            else
            {
                var result = this.CompareCollections(expected, actualElements, path, shouldThrow);
                if (result == ComparisonResult.Failure)
                {
                    return(ComparisonResult.Failure);
                }
            }

            this.AddToLogBuffer("Verifying collection value. Path: {0} SUCCESSFUL", path);

            return(ComparisonResult.Success);
        }
Beispiel #2
0
        protected virtual ComparisonResult CompareCollections(QueryCollectionValue expected, IEnumerable <object> actualElements, string path, bool shouldThrow)
        {
            var actualElementsList = new List <object>(actualElements);

            for (int i = 0; i < expected.Elements.Count; i++)
            {
                var expectedElement = expected.Elements[i];

                bool   matchFound   = false;
                object foundElement = null;

                // foreaching instead of LINQ for easier debugging
                foreach (var actualElement in actualElementsList)
                {
                    var comparisonResult = this.Compare(expectedElement, actualElement, path + "[" + i + "]", false);
                    if (comparisonResult == ComparisonResult.Success)
                    {
                        matchFound   = true;
                        foundElement = actualElement;
                        actualElementsList.Remove(foundElement);

                        break;
                    }
                }

                if (!matchFound)
                {
                    this.ThrowOrLogError(shouldThrow, "Match not found: {0} in {1}.", expectedElement.ToString(), path);

                    return(ComparisonResult.Failure);
                }
            }

            return(ComparisonResult.Success);
        }
Beispiel #3
0
            /// <summary>
            /// Visits the given QueryValue
            /// </summary>
            /// <param name="value">QueryValue being visited.</param>
            /// <returns>The result of visiting this QueryValue.</returns>
            public QueryValue Visit(QueryCollectionValue value)
            {
                var resultElements = new List <QueryValue>();

                // special case the collection of entities, we want to avoid adding entities that are not visible, rather than returning them as nulls.
                var entityElementType = value.Type.ElementType as QueryEntityType;

                if (entityElementType != null)
                {
                    foreach (var entityElement in value.Elements.Cast <QueryStructuralValue>())
                    {
                        QueryStructuralValue resultEntityElement;
                        if (this.visibleEntitiesGraph.TryGetValue(entityElement, out resultEntityElement))
                        {
                            resultElements.Add(resultEntityElement);
                        }
                    }
                }
                else
                {
                    foreach (var element in value.Elements)
                    {
                        var resultElement = this.ProcessResult(element);
                        resultElements.Add(resultElement);
                    }
                }

                return(value.Type.CreateCollectionWithValues(resultElements));
            }
Beispiel #4
0
        private QueryValue ApplySelectAndExpand(ODataUri uri, QueryValue value)
        {
            // Note: this is applied on all URIs, and it is left up to the FixupPropertiesForExpand helper method
            // to skip cases where it is not an entity type
            var expandedPaths = uri.ExpandSegments.Select(s => this.UriConverter.ConcatenateSegments(s));

            value = this.VisitEntityValues(value, s => this.FixupPropertiesForExpand(s, expandedPaths));
            var collection = value as QueryCollectionValue;

            // since we remove expand expression earlier, we need explictly examine it here and set correct IsSorted value for collections.
            if (collection != null)
            {
                var strategy = collection.Type.ElementType.EvaluationStrategy as ILinqToAstoriaQueryEvaluationStrategy;
                ExceptionUtilities.CheckObjectNotNull(strategy, "Cannot get astoria-specific evaluation strategy from collection value.");

                if (uri.ExpandSegments.Any() && !strategy.IsCollectionOrderPredictable)
                {
                    value = QueryCollectionValue.Create(collection.Type.ElementType, collection.Elements, false);
                }
            }

            // if there are any select segments, then fixup the value
            if (uri.SelectSegments.Count > 0)
            {
                // post-process the result to omit properties that were not selected
                var selectedPaths = uri.SelectSegments.Select(s => this.UriConverter.ConcatenateSegments(s.Where(s2 => !(s2 is EntityTypeSegment))));
                value = this.VisitEntityValues(value, s => this.FixupPropertiesForSelect(s, selectedPaths));
            }

            return(value);
        }
Beispiel #5
0
        private void CompareBagPropertyWithNullOrEmpty(QueryStructuralValue instance, QueryProperty memberProperty, string propertyPath, IEnumerable <NamedValue> namedValues)
        {
            List <NamedValue> exactMatches = namedValues.Where(nv => nv.Name == propertyPath).ToList();

            if (!exactMatches.Any())
            {
                return;
            }

            ExceptionUtilities.Assert(exactMatches.Count == 1, "Should only find at most one property path {0} when looking for null or empty value", propertyPath);

            QueryCollectionValue actualQueryBagValue = instance.GetCollectionValue(memberProperty.Name);
            NamedValue           expectedBagValue    = exactMatches.Single();

            if (expectedBagValue.Value == null)
            {
                this.WriteErrorIfNotNull(propertyPath, actualQueryBagValue);
                this.unusedNamedValuePaths.Remove(propertyPath);
            }
            else if (expectedBagValue.Value == EmptyData.Value)
            {
                if (!this.WriteErrorIfNull(propertyPath, actualQueryBagValue))
                {
                    this.WriteErrorIfNotEqual(propertyPath, actualQueryBagValue.Elements.Count, 0, "Expected zero elements in BagProperty");
                    this.unusedNamedValuePaths.Remove(propertyPath);
                }
            }
        }
Beispiel #6
0
 private void SetCollectionValue(QueryCollectionValue queryCollectionValue, List <QueryValue> collectionElements)
 {
     queryCollectionValue.Elements.Clear();
     foreach (QueryValue queryValue in collectionElements)
     {
         queryCollectionValue.Elements.Add(queryValue);
     }
 }
        /// <summary>
        /// Computes the Maximum value of a collection as a <see cref="QueryScalarValue"/>.
        /// </summary>
        /// <param name="collection">The collection of values.</param>
        /// <returns>The min value.</returns>
        public QueryScalarValue Min(QueryCollectionValue collection)
        {
            ExceptionUtilities.Assert(collection.Type.ElementType is QueryScalarType, "Min can only be applied on scalar types");
            ExceptionUtilities.Assert(collection.Elements.Any(v => !v.IsNull), "Collection must contain at least one non-null value in a Min operation");

            var type = collection.Type.ElementType as QueryScalarType;

            return(type.CreateValue(collection.Elements.Cast <QueryScalarValue>().Min(sv => sv.Value)));
        }
        protected virtual ComparisonResult CompareCollections(QueryCollectionValue expected, IEnumerable <object> actualElements, string path, bool shouldThrow, out bool comparisonSkippedForAnyElement)
        {
            comparisonSkippedForAnyElement = false;

            List <object> actualElementsList = new List <object>(actualElements);

            for (int i = 0; i < expected.Elements.Count; i++)
            {
                var expectedElement = expected.Elements[i];

                bool          matchFound             = false;
                object        foundElement           = null;
                List <object> filteredActualElements = new List <object>(actualElements);
#if !SILVERLIGHT
                // This was added for debugging purposes, on Silverlight it fails due to reflection calls so commenting it out
                filteredActualElements = this.FilterOutNonEqualActualElements(expectedElement, actualElements);
#endif

                // foreaching instead of LINQ for easier debugging
                foreach (var actualElement in filteredActualElements)
                {
                    var comparisonResult = this.Compare(expectedElement, actualElement, path + "[" + i + "]", false);
                    if (comparisonResult != ComparisonResult.Failure)
                    {
                        matchFound   = true;
                        foundElement = actualElement;

                        // remove the element from the actual elements only if the result is 'Success', and leave it for 'Skipped'
                        if (comparisonResult == ComparisonResult.Success)
                        {
                            actualElementsList.Remove(foundElement);
                        }
                        else
                        {
                            comparisonSkippedForAnyElement = true;
                        }

                        break;
                    }
                }

                // if after comparison we still have actual elements left, and all these elements are in ObjectStateManager it means that
                // we may have skipped verification for some elements and therefore should return 'Skipped'
                if (actualElementsList.Count > 0 && actualElementsList.All(ae => this.LinqResultComparerContextAdapter.IsObjectTrackedByContext(ae)))
                {
                    comparisonSkippedForAnyElement = true;
                }

                if (!matchFound)
                {
                    this.ThrowOrLogError(shouldThrow, "Match not found: {0} in {1}.", expectedElement.ToString(), path);
                    return(ComparisonResult.Failure);
                }
            }

            return(ComparisonResult.Success);
        }
Beispiel #9
0
 private void UpdateVisibleEntitiesGraphForCollection(QueryCollectionValue collectionValue, string path, string[] spanPaths)
 {
     if (!collectionValue.IsNull)
     {
         foreach (var element in collectionValue.Elements)
         {
             this.UpdateVisibleEntitiesGraphForQueryValue(element, path, spanPaths);
         }
     }
 }
Beispiel #10
0
        private void SetCollectionProperty(QueryStructuralValue instance, QueryProperty memberProperty, List <QueryValue> collectionElements)
        {
            QueryCollectionValue queryCollectionValue = instance.GetCollectionValue(memberProperty.Name);

            queryCollectionValue.Elements.Clear();
            foreach (QueryValue queryValue in collectionElements)
            {
                queryCollectionValue.Elements.Add(queryValue);
            }

            instance.SetValue(memberProperty.Name, queryCollectionValue);
        }
Beispiel #11
0
        /// <summary>
        /// Helper method for visiting a collection of values invoking a callback on all structural values
        /// </summary>
        /// <param name="collection">The collection to visit</param>
        /// <param name="callback">The callback for structural values</param>
        /// <returns>The result of visiting the collection</returns>
        private QueryCollectionValue VisitEntityValues(QueryCollectionValue collection, Func <QueryStructuralValue, QueryStructuralValue> callback)
        {
            ExceptionUtilities.CheckArgumentNotNull(collection, "collection");
            ExceptionUtilities.CheckArgumentNotNull(callback, "callback");

            var type = collection.Type.ElementType as QueryEntityType;

            ExceptionUtilities.CheckObjectNotNull(type, "Collection element type was not an entity type. Type was: {0}", collection.Type.ElementType);

            // in general, we want to return a different instance so that the value stored in the query data set are not affected
            return(collection.Select(v => this.VisitEntityValues(v, callback)));
        }
Beispiel #12
0
        /// <summary>
        /// Visits the QueryCollectionValue
        /// </summary>
        /// <param name="value">Value to visit</param>
        /// <returns>a null value</returns>
        public string Visit(QueryCollectionValue value)
        {
            if (value.Elements != null)
            {
                foreach (var element in value.Elements)
                {
                    element.Accept(this);
                }
            }

            return(null);
        }
Beispiel #13
0
        /// <summary>
        /// Builds an instance of QueryCollectionValue from an entity set instance.
        /// </summary>
        /// <param name="entitySetInstance">The entity set instance.</param>
        /// <param name="elementType">The QueryEntityType of its element.</param>
        /// <param name="xmlBaseAnnotations">The xml base annotations from parent elements, if any</param>
        /// <returns>The converted QueryCollectionValue of entity set instance.</returns>
        private QueryCollectionValue BuildFromEntitySetInstance(EntitySetInstance entitySetInstance, QueryEntityType elementType, IEnumerable <XmlBaseAnnotation> xmlBaseAnnotations)
        {
            ExceptionUtilities.CheckArgumentNotNull(elementType, "elementType");
            var entities = new List <QueryStructuralValue>();

            foreach (var entityInstance in entitySetInstance)
            {
                var value = this.BuildFromEntityInstance(entityInstance, elementType, xmlBaseAnnotations.Concat(entityInstance.Annotations.OfType <XmlBaseAnnotation>()));
                entities.Add(value);
            }

            return(QueryCollectionValue.Create(elementType, entities.ToArray()));
        }
 /// <summary>
 /// Creates a copy of the given value recursively
 /// </summary>
 /// <param name="value">The value to copy</param>
 /// <returns>The copied value</returns>
 public QueryValue Visit(QueryCollectionValue value)
 {
     return(this.HandleCommonCasesAndCache(
                value,
                () => value.Type.CreateCollectionWithValues(Enumerable.Empty <QueryValue>()),
                copy =>
     {
         var collectionCopy = (QueryCollectionValue)copy;
         foreach (var element in value.Elements)
         {
             collectionCopy.Elements.Add(element.Accept(this));
         }
     }));
 }
Beispiel #15
0
        /// <summary>
        /// Adds an ordering expression for each key property
        /// </summary>
        /// <param name="queryCollectionValue">QueryCollection Value to sort</param>
        /// <returns>The result of adding the ordering expressions</returns>
        private QueryCollectionValue AddOrderingForPagingToQueryCollectionValue(QueryCollectionValue queryCollectionValue)
        {
            ExceptionUtilities.CheckArgumentNotNull(queryCollectionValue, "queryCollectionValue");

            ExceptionUtilities.CheckObjectNotNull(this.expectedEntitySet, "No entity set expected");
            var queryEntityType = (QueryEntityType)queryCollectionValue.Type.ElementType;

            var orderedElements = queryCollectionValue.Elements.OfType <QueryStructuralValue>();

            // the product will sort key properties alphabetically
            foreach (var key in queryEntityType.EntityType.AllKeyProperties.OrderBy(p => p.Name))
            {
                orderedElements = orderedElements.OrderBy(o => o.GetScalarValue(key.Name).Value);
            }

            return(QueryCollectionValue.Create(queryCollectionValue.Type.ElementType, orderedElements.ToArray()));
        }
Beispiel #16
0
        private static QueryValue EnsureLastSegmentIsSingletonOrNull(QueryValue value)
        {
            QueryCollectionValue collection = value as QueryCollectionValue;

            if (collection != null)
            {
                if (collection.IsNull || collection.Elements.Count == 0)
                {
                    value = collection.Type.ElementType.NullValue;
                }
                else
                {
                    value = collection.Elements.Single();
                }
            }

            return(value);
        }
        internal void UpdateValues(QueryCollectionValue queryCollectionValue, IEnumerable<NamedValue> namedValues)
        {
            ExceptionUtilities.CheckArgumentNotNull(queryCollectionValue, "queryCollectionValue");
            ExceptionUtilities.CheckArgumentNotNull(namedValues, "namedValues");

            var primitiveElementDataType = queryCollectionValue.Type.ElementType as QueryClrPrimitiveType;
            if (primitiveElementDataType != null)
            {
                this.UpdateRootScalarBag(queryCollectionValue, namedValues, primitiveElementDataType);
            }
            else
            {
                var complexElementDataType = queryCollectionValue.Type.ElementType as QueryComplexType;
                ExceptionUtilities.CheckObjectNotNull(complexElementDataType, "Expected QueryComplex Type, actual query type {0}", queryCollectionValue.Type);

                this.UpdateRootComplexBag(queryCollectionValue, namedValues, complexElementDataType);
            }
        }
Beispiel #18
0
        internal void UpdateValues(QueryCollectionValue queryCollectionValue, IEnumerable <NamedValue> namedValues)
        {
            ExceptionUtilities.CheckArgumentNotNull(queryCollectionValue, "queryCollectionValue");
            ExceptionUtilities.CheckArgumentNotNull(namedValues, "namedValues");

            var primitiveElementDataType = queryCollectionValue.Type.ElementType as QueryClrPrimitiveType;

            if (primitiveElementDataType != null)
            {
                this.UpdateRootScalarBag(queryCollectionValue, namedValues, primitiveElementDataType);
            }
            else
            {
                var complexElementDataType = queryCollectionValue.Type.ElementType as QueryComplexType;
                ExceptionUtilities.CheckObjectNotNull(complexElementDataType, "Expected QueryComplex Type, actual query type {0}", queryCollectionValue.Type);

                this.UpdateRootComplexBag(queryCollectionValue, namedValues, complexElementDataType);
            }
        }
        private QueryCollectionValue RewriteGroupingElements(QueryCollectionValue groupings, LinqLambdaExpression elementSelectorLambda)
        {
            var groupingElementType   = (QueryGroupingType)groupings.Type.ElementType;
            var rewrittenGroupingType = new QueryGroupingType(groupingElementType.Key.PropertyType, elementSelectorLambda.Body.ExpressionType, groupingElementType.EvaluationStrategy);

            var rewrittenGroupings = new List <QueryValue>();

            foreach (var grouping in groupings.Elements.Cast <QueryStructuralValue>())
            {
                QueryCollectionValue elements = grouping.GetCollectionValue("Elements");
                var rewrittenElements         = elements.Select(e => this.EvaluateLambda <QueryValue>(elementSelectorLambda, e));
                var rewrittenGrouping         = rewrittenGroupingType.CreateNewInstance();
                rewrittenGrouping.SetValue("Key", grouping.GetValue("Key"));
                rewrittenGrouping.SetValue("Elements", rewrittenElements);
                rewrittenGroupings.Add(rewrittenGrouping);
            }

            var result = rewrittenGroupingType.CreateCollectionType().CreateCollectionWithValues(rewrittenGroupings);

            return(result);
        }
Beispiel #20
0
            /// <summary>
            /// Evaluates the specified expression.
            /// </summary>
            /// <param name="expression">The expression to evaluate.</param>
            /// <returns>Value of the expression.</returns>
            public override QueryValue Visit(LinqOrderByExpression expression)
            {
                var value = this.VisitCollectionElementPrimitiveOrComplexTypeError(
                    expression,
                    delegate
                {
                    return(base.Visit(expression));
                });

                var collection = value as QueryCollectionValue;
                var strategy   = collection.Type.ElementType.EvaluationStrategy as ILinqToAstoriaQueryEvaluationStrategy;

                ExceptionUtilities.CheckObjectNotNull(strategy, "Cannot get astoria-specific evaluation strategy from collection value.");

                if (strategy.IsCollectionOrderPredictable)
                {
                    return(QueryCollectionValue.Create(collection.Type.ElementType, collection.Elements, true));
                }

                return(value);
            }
        /// <summary>
        /// Initializes query collection values.
        /// </summary>
        /// <param name="entitySetData">entity set data</param>
        /// <returns>initial query collection value</returns>
        protected virtual QueryCollectionValue BuildStubEntities(EntitySetData entitySetData)
        {
            string entitySetName = entitySetData.EntitySet.Name;

            var elements  = new List <QueryStructuralValue>();
            var setRowMap = new Dictionary <EntityDataKey, QueryStructuralValue>();

            foreach (EntitySetDataRow row in entitySetData.Rows)
            {
                var queryType = this.GetQueryType(entitySetData.EntitySet.Name, row.EntityType);
                var instance  = this.InitializeEntityValue(queryType);

                setRowMap[row.Key] = instance;
                elements.Add(instance);
            }

            this.rowInstances[entitySetName] = setRowMap;

            var rootElementType = this.GetQueryType(entitySetName, entitySetData.EntitySet.EntityType);

            return(QueryCollectionValue.Create(rootElementType, elements.ToArray()));
        }
Beispiel #22
0
        private void UpdateRootComplexBag(QueryCollectionValue queryCollectionValue, IEnumerable <NamedValue> namedValues, QueryComplexType complexTypeElementDataType)
        {
            int i = 0;

            var complexCollection = new List <QueryValue>();
            List <NamedValue> complexInstanceNamedValues = namedValues.Where(pp => pp.Name.StartsWith(i + ".", StringComparison.Ordinal)).ToList();

            while (complexInstanceNamedValues.Any())
            {
                QueryStructuralValue complexValue = complexTypeElementDataType.CreateNewInstance();
                this.UpdateValues(complexValue, complexInstanceNamedValues, i.ToString(CultureInfo.InvariantCulture));
                complexCollection.Add(complexValue);

                i++;
                complexInstanceNamedValues = namedValues.Where(pp => pp.Name.StartsWith(i + ".", StringComparison.Ordinal)).ToList();
            }

            if (complexCollection.Any())
            {
                this.SetCollectionValue(queryCollectionValue, complexCollection);
            }
        }
Beispiel #23
0
            /// <summary>
            /// Visits a LinqExpandExpression.
            /// </summary>
            /// <param name="expression">The expression.</param>
            /// <returns>Value of the expression</returns>
            public QueryValue Visit(LinqToAstoriaExpandExpression expression)
            {
                // expand is not handled here, instead it's handled in the trimming phase after
                // the whole expression has been evaluated
                var expanded = this.Evaluate(expression.Source);

                // if expanding a collection using sql strategy, we do not guarantee the order of top level set.
                var collection = expanded as QueryCollectionValue;

                if (collection != null)
                {
                    var strategy = collection.Type.ElementType.EvaluationStrategy as ILinqToAstoriaQueryEvaluationStrategy;
                    ExceptionUtilities.CheckObjectNotNull(strategy, "Cannot get astoria-specific evaluation strategy from collection value.");

                    if (!strategy.IsCollectionOrderPredictable)
                    {
                        return(QueryCollectionValue.Create(collection.Type.ElementType, collection.Elements, false));
                    }
                }

                return(expanded);
            }
Beispiel #24
0
        /// <summary>
        /// Gets the expected query value for the action request
        /// </summary>
        /// <param name="initialExpectedResults">Initial expected values for an action</param>
        /// <param name="parameterValues">Parameter values for the action</param>
        /// <returns>A query Value that is the expected value</returns>
        public QueryValue GetExpectedQueryValue(QueryValue initialExpectedResults, params QueryValue[] parameterValues)
        {
            ExceptionUtilities.CheckArgumentNotNull(initialExpectedResults, "initialExpectedResults");
            if (initialExpectedResults.IsNull || this.ReturnProperty == null)
            {
                return(initialExpectedResults.Type.NullValue);
            }

            QueryStructuralValue initialStructuralValue = initialExpectedResults as QueryStructuralValue;
            QueryCollectionValue initialCollectionValue = initialExpectedResults as QueryCollectionValue;

            if (initialStructuralValue != null)
            {
                return(initialStructuralValue.GetValue(this.ReturnProperty));
            }
            else
            {
                ExceptionUtilities.CheckArgumentNotNull(initialCollectionValue, "Unsupported initialExpectedResults type.");
                if (initialCollectionValue.Elements.Count > 0)
                {
                    // Sort the results by the keys
                    var queryEntityType = (QueryEntityType)initialCollectionValue.Type.ElementType;
                    var sortedList      = initialCollectionValue.Elements.Select(r => (QueryStructuralValue)r).ToList();
                    foreach (var key in queryEntityType.EntityType.AllKeyProperties)
                    {
                        sortedList = sortedList.OrderBy(r => r.GetScalarValue(key.Name).Value).ToList();
                    }

                    var firstItemValue = (QueryStructuralValue)sortedList.First();
                    ExceptionUtilities.CheckArgumentNotNull(firstItemValue, "firstItemValue");
                    return(firstItemValue.GetValue(this.ReturnProperty));
                }
                else
                {
                    return(initialCollectionValue.Type.ElementType.NullValue);
                }
            }
        }
Beispiel #25
0
        private void UpdateRootScalarBag(QueryCollectionValue instance, IEnumerable <NamedValue> namedValues, QueryScalarType scalarElementDataType)
        {
            int i = 0;

            var scalarCollection = new List <QueryValue>();
            List <NamedValue> scalarItemNamedValues = namedValues.Where(pp => pp.Name == i.ToString(CultureInfo.InvariantCulture)).ToList();

            while (scalarItemNamedValues.Any())
            {
                ExceptionUtilities.Assert(scalarItemNamedValues.Count() < 2, "Should not get more than one value for a scalar Bag item for path '{0}'", i.ToString(CultureInfo.InvariantCulture));
                var value = scalarItemNamedValues.Single();
                scalarCollection.Add(scalarElementDataType.CreateValue(value.Value));
                this.unusedNamedValuePaths.Remove(value.Name);

                i++;
                scalarItemNamedValues = namedValues.Where(pp => pp.Name == i.ToString(CultureInfo.InvariantCulture)).ToList();
            }

            if (scalarCollection.Any())
            {
                this.SetCollectionValue(instance, scalarCollection);
            }
        }
        /// <summary>
        /// Filters the specified source using given predicate.
        /// </summary>
        /// <typeparam name="TElement">The type of the element.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="predicate">The predicate.</param>
        /// <returns>
        /// Filtered collection (including elements where the predicate matches).
        /// </returns>
        /// <remarks>The value can be store-dependent w.r.t. handling of NULL values of the input collection
        /// and/or result of the predicate.</remarks>
        public QueryCollectionValue Filter(QueryCollectionValue source, Func <QueryValue, QueryScalarValue> predicate)
        {
            ExceptionUtilities.CheckArgumentNotNull(source, "source");

            IEnumerable <QueryValue> result = null;

            if (!source.IsNull)
            {
                result = source.Elements.Where(
                    c =>
                {
                    var evaluatedValue = predicate(c);
                    if (evaluatedValue.IsNull)
                    {
                        return(false);
                    }

                    return((bool)evaluatedValue.Value);
                });
            }

            return(new QueryCollectionValue(source.Type, this, QueryError.GetErrorFromValues(result), result, source.IsSorted));
        }
        /// <summary>
        /// Builds an instance of QueryCollectionValue from an entity set instance.
        /// </summary>
        /// <param name="entitySetInstance">The entity set instance.</param>
        /// <param name="elementType">The QueryEntityType of its element.</param>
        /// <param name="xmlBaseAnnotations">The xml base annotations from parent elements, if any</param>
        /// <returns>The converted QueryCollectionValue of entity set instance.</returns>
        private QueryCollectionValue BuildFromEntitySetInstance(EntitySetInstance entitySetInstance, QueryEntityType elementType, IEnumerable<XmlBaseAnnotation> xmlBaseAnnotations)
        {
            ExceptionUtilities.CheckArgumentNotNull(elementType, "elementType");
            var entities = new List<QueryValue>();
            QueryValue value;

            foreach (var instance in entitySetInstance)
            {
                EntityInstance entity = instance as EntityInstance;
                if (entity != null)
                {
                    value = this.BuildFromEntityInstance(entity, elementType, xmlBaseAnnotations.Concat(entity.Annotations.OfType<XmlBaseAnnotation>()));
                }
                else
                {
                    value = this.BuildFromPrimitive((PrimitiveValue)instance, elementType);
                }

                entities.Add(value);
            }

            return QueryCollectionValue.Create(elementType, entities.ToArray());
        }
        /// <summary>
        /// Evaluates the specified expression.
        /// </summary>
        /// <param name="expression">The expression to evaluate.</param>
        /// <returns>Value of the expression.</returns>
        public virtual QueryValue Visit(LinqNewInstanceExpression expression)
        {
            if (expression.ExpressionType is QueryStructuralType)
            {
                QueryStructuralType  queryType = (QueryStructuralType)expression.ExpressionType;
                QueryStructuralValue instance  = queryType.CreateNewInstance();

                foreach (var property in queryType.Properties.Where(p => !(p.PropertyType is QueryScalarType)))
                {
                    instance.SetValue(property.Name, property.PropertyType.DefaultValue);
                }

                for (int i = 0; i < expression.Members.Count; ++i)
                {
                    instance.SetValue(expression.MemberNames[i], this.Evaluate(expression.Members[i]));
                }

                return(instance);
            }
            else if (expression.ExpressionType is QueryCollectionType)
            {
                // for QueryCollectionTypes we only support constructor arguments, hence we will only be evaluating constructor arguments.
                QueryCollectionValue instance = ((QueryCollectionType)expression.ExpressionType).CreateCollectionWithValues(expression.ConstructorArguments.Select(arg => this.Evaluate(arg)));

                return(instance);
            }
            else
            {
                var scalarType = expression.ExpressionType as QueryScalarType;
                ExceptionUtilities.CheckObjectNotNull(scalarType, "QueryType is not a supported type");
                ExceptionUtilities.Assert(expression.ConstructorArguments.Count == 1, "Cannot pass multiple arguments to PrimitiveType constructor");
                var constructorArgument   = expression.ConstructorArguments.Select(this.Evaluate).Single();
                QueryScalarValue instance = scalarType.CreateValue(constructorArgument);

                return(instance);
            }
        }
        private QueryValue CloneValue(Dictionary<QueryStructuralValue, QueryStructuralValue> identityMap, QueryValue value)
        {
            // no need to clone scalar values
            if (value is QueryScalarValue)
            {
                return value;
            }

            if (value is AstoriaQueryStreamValue)
            {
                return value;
            }

            QueryStructuralValue qsv = value as QueryStructuralValue;
            if (qsv != null)
            {
                return this.CloneStructuralValue(identityMap, qsv);
            }

            QueryCollectionValue qcv = value as QueryCollectionValue;
            ExceptionUtilities.Assert(qcv != null, "Expected collection value.");

            return this.CloneCollectionValue(identityMap, qcv);
        }
        private void UpdateRootScalarBag(QueryCollectionValue instance, IEnumerable<NamedValue> namedValues, QueryScalarType scalarElementDataType)
        {
            int i = 0;

            var scalarCollection = new List<QueryValue>();
            List<NamedValue> scalarItemNamedValues = namedValues.Where(pp => pp.Name == i.ToString(CultureInfo.InvariantCulture)).ToList();
            while (scalarItemNamedValues.Any())
            {
                ExceptionUtilities.Assert(scalarItemNamedValues.Count() < 2, "Should not get more than one value for a scalar Bag item for path '{0}'", i.ToString(CultureInfo.InvariantCulture));
                var value = scalarItemNamedValues.Single();
                scalarCollection.Add(scalarElementDataType.CreateValue(value.Value));
                this.unusedNamedValuePaths.Remove(value.Name);

                i++;
                scalarItemNamedValues = namedValues.Where(pp => pp.Name == i.ToString(CultureInfo.InvariantCulture)).ToList();
            }

            if (scalarCollection.Any())
            {
                this.SetCollectionValue(instance, scalarCollection);
            }
        }
Beispiel #31
0
        /// <summary>
        /// Adds an ordering expression for each key property 
        /// </summary>
        /// <param name="queryCollectionValue">QueryCollection Value to sort</param>
        /// <returns>The result of adding the ordering expressions</returns>
        private QueryCollectionValue AddOrderingForPagingToQueryCollectionValue(QueryCollectionValue queryCollectionValue)
        {
            ExceptionUtilities.CheckArgumentNotNull(queryCollectionValue, "queryCollectionValue");

            ExceptionUtilities.CheckObjectNotNull(this.expectedEntitySet, "No entity set expected");
            var queryEntityType = (QueryEntityType)queryCollectionValue.Type.ElementType;

            var orderedElements = queryCollectionValue.Elements.OfType<QueryStructuralValue>();

            // the product will sort key properties alphabetically
            foreach (var key in queryEntityType.EntityType.AllKeyProperties.OrderBy(p => p.Name))
            {
                orderedElements = orderedElements.OrderBy(o => o.GetScalarValue(key.Name).Value);
            }

            return QueryCollectionValue.Create(queryCollectionValue.Type.ElementType, orderedElements.ToArray());
        }
Beispiel #32
0
        /// <summary>
        /// Helper method for visiting a collection of values invoking a callback on all structural values
        /// </summary>
        /// <param name="collection">The collection to visit</param>
        /// <param name="callback">The callback for structural values</param>
        /// <returns>The result of visiting the collection</returns>
        private QueryCollectionValue VisitEntityValues(QueryCollectionValue collection, Func<QueryStructuralValue, QueryStructuralValue> callback)
        {
            ExceptionUtilities.CheckArgumentNotNull(collection, "collection");
            ExceptionUtilities.CheckArgumentNotNull(callback, "callback");

            var type = collection.Type.ElementType as QueryEntityType;
            ExceptionUtilities.CheckObjectNotNull(type, "Collection element type was not an entity type. Type was: {0}", collection.Type.ElementType);

            // in general, we want to return a different instance so that the value stored in the query data set are not affected
            return collection.Select(v => this.VisitEntityValues(v, callback)); 
        }
        /// <summary>
        /// Clones the collection (returns a new collection where all elements are clones of existing elements in the source collection)
        /// </summary>
        /// <param name="identityMap">The identity map.</param>
        /// <param name="collectionValue">The collection value.</param>
        /// <returns>New collection where all elements are clones of existing elements in the source collection.</returns>
        private QueryCollectionValue CloneCollectionValue(Dictionary<QueryStructuralValue, QueryStructuralValue> identityMap, QueryCollectionValue collectionValue)
        {
            if (collectionValue.IsNull)
            {
                return collectionValue.Type.NullValue;
            }

            var clonedValues = collectionValue.Elements.Select(c => this.CloneValue(identityMap, c)).ToList();
            return collectionValue.Type.CreateCollectionWithValues(clonedValues);
        }
 private void SetCollectionValue(QueryCollectionValue queryCollectionValue, List<QueryValue> collectionElements)
 {
     queryCollectionValue.Elements.Clear();
     foreach (QueryValue queryValue in collectionElements)
     {
         queryCollectionValue.Elements.Add(queryValue);
     }
 }
            /// <summary>
            /// verification method to verify entity collection without verifying order.
            /// </summary>
            /// <param name="payloadElement">entity set instance</param>
            /// <param name="value">expected collection value</param>
            private void CompareUnsortedCollection(EntitySetInstance payloadElement, QueryCollectionValue value)
            {
                for (int i = 0; i < payloadElement.Count; i++)
                {
                    var actual = payloadElement[i];
                    ExceptionUtilities.CheckObjectNotNull(actual, "Element at position {0} was unexpectedly null", i);

                    bool match = false;
                    foreach (var expected in value.Elements)
                    {
                        var ex = this.RecurseAndCatch(actual, expected);
                        if (ex == null)
                        {
                            match = true;
                            break;
                        }
                    }

                    this.parent.Assert.IsTrue(match, "Element at position {0} did not match any expected value", i + 1);
                }
            }
Beispiel #36
0
        /// <summary>
        /// Build a sub query data set from payload, but having enough information and correct order for evaluation.
        /// </summary>
        /// <param name="payload">The ODataPayloadElement converted from payload.</param>
        /// <returns>A sub query data set containing converted query value.</returns>
        private IQueryDataSet BuildQueryDataSet(ODataPayloadElement payload)
        {
            var dataSet = new QueryDataSet();

            var xmlBaseAnnotations = payload.Annotations.OfType <XmlBaseAnnotation>();

            var entityInstance = payload as EntityInstance;

            if (entityInstance != null)
            {
                // get QueryEntityType for entity instance. Notice that even we are expecting an anonymous type from projection, we still need to find out the 'original' entity type, since we need to build a query data set.
                var elementType = this.currentExpression.ExpressionType as QueryEntityType;
                if (elementType == null)
                {
                    var collectionType = this.currentExpression.ExpressionType as QueryCollectionType;
                    ExceptionUtilities.CheckObjectNotNull(collectionType, "Cannot cast expression type to QueryCollectionType.");

                    elementType = collectionType.ElementType as QueryEntityType;
                    if (elementType == null)
                    {
                        var anonymousType = collectionType.ElementType as QueryAnonymousStructuralType;
                        ExceptionUtilities.CheckArgumentNotNull(anonymousType, "It must be an anonymous type if it is not an entity type.");

                        // TODO: It may have problems if client side's entity types have diferent names with those on server side.
                        // A solution is implementing another query expression visitor, removing all the $select expression, and using the type from expression.ExpressionType.
                        elementType = this.GetQueryEntityTypeByFullTypeName(entityInstance.FullTypeName);
                    }
                }

                // build query value and store it in query data set.
                var entity     = this.BuildFromEntityInstance(entityInstance, elementType, xmlBaseAnnotations);
                var collection = QueryCollectionValue.Create(this.DefaultDataSet[elementType.EntitySet.Name].Type.ElementType, new List <QueryValue>()
                {
                    entity
                }, true);
                dataSet.RootQueryData.Add(elementType.EntitySet.Name, collection);
            }
            else
            {
                var entitySetInstance = payload as EntitySetInstance;
                ExceptionUtilities.CheckObjectNotNull(entitySetInstance, "Payload was neither a feed nor entity. Type was: {0}", payload.ElementType);

                var collectionType = this.currentExpression.ExpressionType as QueryCollectionType;
                ExceptionUtilities.CheckObjectNotNull(collectionType, "Cannot cast expression type to QueryCollectionType.");

                var elementType = collectionType.ElementType as QueryEntityType;
                if (elementType == null)
                {
                    var anonymousType = collectionType.ElementType as QueryAnonymousStructuralType;
                    ExceptionUtilities.CheckArgumentNotNull(anonymousType, "It must be an anonymous type if it is not an entity type.");

                    var title = entitySetInstance.Annotations.OfType <TitleAnnotation>().SingleOrDefault();
                    ExceptionUtilities.CheckObjectNotNull(title, "Cannot find title information from entity set instance.");

                    ExceptionUtilities.CheckObjectNotNull(title.Value, "Cannot get title value from entity set instance.");
                    QueryStructuralType rootDataType;
                    this.QueryRepository.RootDataTypes.TryGetValue(title.Value, out rootDataType);
                    if (rootDataType == null)
                    {
                        this.RootDataTypesDerivedTypes().TryGetValue(title.Value, out rootDataType);
                    }

                    ExceptionUtilities.CheckObjectNotNull(rootDataType, "Cannot find title value '{0}' in root datatypes", title.Value);
                    elementType = rootDataType as QueryEntityType;
                    ExceptionUtilities.CheckObjectNotNull(elementType, "Cannot find element type for entity set '{0}'.", title.Value);
                }

                var collection = this.BuildFromEntitySetInstance(entitySetInstance, elementType, xmlBaseAnnotations);
                dataSet.RootQueryData.Add(elementType.EntitySet.Name, collection);
            }

            return(dataSet);
        }
 /// <summary>
 /// verification method to verify entity collection with predictable order.
 /// </summary>
 /// <param name="payloadElement">entity set instance</param>
 /// <param name="value">expected collection value</param>
 private void CompareSortedCollection(EntitySetInstance payloadElement, QueryCollectionValue value)
 {
     for (int i = 0; i < value.Elements.Count; i++)
     {
         this.RecurseWithMessage(payloadElement[i], value.Elements[i], "Element at position {0} did not match expectation", i + 1);
     }
 }
        /// <summary>
        /// Compares collection object with the expected value.
        /// </summary>
        /// <param name="expected">Expected value.</param>
        /// <param name="actual">Actual value.</param>
        /// <param name="path">The path to the compared object (for debugging purposes).</param>
        /// <param name="shouldThrow">Should exception be thrown if error is encountered.</param>
        /// <returns>Result of the comparison, Success, Failure or Skipped.</returns>
        protected ComparisonResult CompareCollection(QueryCollectionValue expected, object actual, string path, bool shouldThrow)
        {
            this.AddToLogBuffer("Verifying collection value. Path: {0}", path);

            if (actual == null)
            {
                if (expected.IsNull)
                {
                    return(ComparisonResult.Success);
                }

                this.ThrowOrLogError(shouldThrow, "Expecting non-null value: {0} in '{1}'. Got null instead.", expected, path);

                return(ComparisonResult.Failure);
            }

            IEnumerable actualCollection = actual as IEnumerable;

            if (expected.IsNull)
            {
                return(this.ProcessExpectedNullCollection(actual, actualCollection, path, shouldThrow));
            }

            if (actualCollection == null)
            {
                this.ThrowOrLogError(shouldThrow, "Expecting a collection in '{0}'.", path);

                return(ComparisonResult.Failure);
            }

            List <object> actualElements = actualCollection.Cast <object>().ToList();

            if (expected.Type.ElementType is QueryEntityType)
            {
                // for collection of entities, if we expect more elements than there is, collections are surely not equivalent
                // if there are more elements than expected however, it may mean that some of them are in the ObjectStateManager,
                // so we need to accomodate for that
                if (expected.Elements.Count() > actualElements.Count)
                {
                    this.ThrowOrLogError(shouldThrow, "Collection element counts do not match in '{0}'. Expected: {1}. Actual: {2}.", path, expected.Elements.Count(), actualElements.Count);

                    return(ComparisonResult.Failure);
                }
            }
            else
            {
                // for collection of non-entities there is no need to look up in the ObjectStateManager, if the counts don't match we can return 'Failed'
                if (expected.Elements.Count() != actualElements.Count)
                {
                    this.ThrowOrLogError(shouldThrow, "Collection element counts do not match in '{0}'. Expected: {1}. Actual: {2}.", path, expected.Elements.Count(), actualElements.Count);

                    return(ComparisonResult.Failure);
                }
            }

            bool comparisonSkippedForAnyElement = false;

            if (expected.IsSorted)
            {
                if (expected.Elements.Count() != actualElements.Count)
                {
                    this.ThrowOrLogError(shouldThrow, "Collection element counts do not match in '{0}'. Expected: {1}. Actual: {2}.", path, expected.Elements.Count(), actualElements.Count);

                    return(ComparisonResult.Failure);
                }

                // for sorted collection, compare until first error is found
                // we don't need to take OSM into account, as reference span is only applicable to collections which are not explicitly projected
                // in order to sort the collection, one must explicitly project it as well
                for (int i = 0; i < expected.Elements.Count(); i++)
                {
                    this.Compare(expected.Elements[i], actualElements[i], path + "[" + i + "]", true);
                }
            }
            else
            {
                ComparisonResult result = this.CompareCollections(expected, actualElements, path, shouldThrow, out comparisonSkippedForAnyElement);
                if (result == ComparisonResult.Failure)
                {
                    return(ComparisonResult.Failure);
                }
            }

            if (comparisonSkippedForAnyElement)
            {
                this.AddToLogBuffer("Verifying collection value. Path: {0} SKIPPED", path);

                return(ComparisonResult.Skipped);
            }
            else
            {
                this.AddToLogBuffer("Verifying collection value. Path: {0} SUCCESSFUL", path);

                return(ComparisonResult.Success);
            }
        }
        private void UpdateRootComplexBag(QueryCollectionValue queryCollectionValue, IEnumerable<NamedValue> namedValues, QueryComplexType complexTypeElementDataType)
        {
            int i = 0;

            var complexCollection = new List<QueryValue>();
            List<NamedValue> complexInstanceNamedValues = namedValues.Where(pp => pp.Name.StartsWith(i + ".", StringComparison.Ordinal)).ToList();
            while (complexInstanceNamedValues.Any())
            {
                QueryStructuralValue complexValue = complexTypeElementDataType.CreateNewInstance();
                this.UpdateValues(complexValue, complexInstanceNamedValues, i.ToString(CultureInfo.InvariantCulture));
                complexCollection.Add(complexValue);

                i++;
                complexInstanceNamedValues = namedValues.Where(pp => pp.Name.StartsWith(i + ".", StringComparison.Ordinal)).ToList();
            }

            if (complexCollection.Any())
            {
                this.SetCollectionValue(queryCollectionValue, complexCollection);
            }
        }