protected override async Task FormatAssertAsync(StreamWriter writer)
        {
            var syncResultType  = _methods.SyncMethod.ReturnType;
            var asyncReturnType = _methods.AsyncMethod.ReturnType;
            var asyncResultType = AwaitableTypeDescriptor.GetTypeDescriptor(asyncReturnType).ResultType;

            var isSyncResultFPType = syncResultType == typeof(float) ||
                                     syncResultType == typeof(float?) ||
                                     syncResultType == typeof(double) ||
                                     syncResultType == typeof(double?) ||
                                     syncResultType == typeof(decimal) ||
                                     syncResultType == typeof(decimal?);

            var isAsyncResultFPType = asyncResultType == typeof(float) ||
                                      syncResultType == typeof(float?) ||
                                      syncResultType == typeof(double) ||
                                      syncResultType == typeof(double?) ||
                                      syncResultType == typeof(decimal) ||
                                      syncResultType == typeof(decimal?);

            // Compare with tolerance
            if (isSyncResultFPType && isAsyncResultFPType)
            {
                await writer.WriteLineAsync("            AssertHelper.Equal(expectedResult, result);").ConfigureAwait(false);
            }
            else
            {
                await writer.WriteLineAsync("            Assert.Equal(expectedResult, result);").ConfigureAwait(false);
            }
        }
        public async Task ValueTaskAwaitTest()
        {
            var taskType   = typeof(ValueTask);
            var descriptor = AwaitableTypeDescriptor.GetTypeDescriptor(taskType);

            var   awaitable = descriptor.GetAwaitable(DelayValueTask());
            await awaitable;
        }
        public async Task TaskOfTAwaitTest()
        {
            var taskType   = typeof(Task <int>);
            var descriptor = AwaitableTypeDescriptor.GetTypeDescriptor(taskType);

            var awaitable = descriptor.GetAwaitable(DelayTaskOfT());
            var result    = await awaitable;

            Assert.AreEqual(14, result);
        }
        public void NonAwaitableDescriptionTest()
        {
            var type       = typeof(string);
            var descriptor = AwaitableTypeDescriptor.GetTypeDescriptor(type);

            Assert.IsFalse(descriptor.IsAwaitable);
            Assert.AreEqual(type, descriptor.Type);
            Assert.AreEqual(typeof(string), descriptor.ResultType);
            Assert.IsNull(descriptor.AwaiterType);
        }
        public void ValueTaskOfTDescriptionTest()
        {
            var taskType   = typeof(ValueTask <string>);
            var descriptor = AwaitableTypeDescriptor.GetTypeDescriptor(taskType);

            Assert.IsTrue(descriptor.IsAwaitable);
            Assert.AreEqual(taskType, descriptor.Type);
            Assert.AreEqual(typeof(string), descriptor.ResultType);
            Assert.AreEqual(typeof(ValueTaskAwaiter <string>), descriptor.AwaiterType);
        }
        public async Task AwaitNonAwaitableTypeTest()
        {
            var type       = typeof(string);
            var descriptor = AwaitableTypeDescriptor.GetTypeDescriptor(type);
            var str        = "jknorvn";

            var result = await descriptor.GetAwaitable(str);

            Assert.AreSame(str, result);
        }
        public void TaskDescriptionTest()
        {
            var taskType   = typeof(Task);
            var descriptor = AwaitableTypeDescriptor.GetTypeDescriptor(taskType);

            Assert.IsTrue(descriptor.IsAwaitable);
            Assert.AreEqual(taskType, descriptor.Type);
            Assert.AreEqual(typeof(void), descriptor.ResultType);
            Assert.AreEqual(typeof(TaskAwaiter), descriptor.AwaiterType);
        }
        public async ValueTask <TResult> ExecuteAsync <TResult>(Expression expression, CancellationToken token)
        {
            if (expression is null)
            {
                throw new ArgumentNullException(nameof(expression));
            }

            var expressionTypeDescriptor = AwaitableTypeDescriptor.GetTypeDescriptor(expression.Type);
            var expressionResultType     = expressionTypeDescriptor.ResultType;

            if (!expressionResultType.IsAssignableTo <TResult>())
            {
                throw new ArgumentException(
                          $"The expression type must either be assignable to {typeof(TResult)} or an awaitable type with a result type of {typeof(TResult)}.", nameof(expression));
            }

            // Rewrite the recorded expression, in order to perform as many of the query processing in the database
            // engine (or the database driver) which will be highly optimized by them. Fall back to in memory processing
            // only if necessary as a post-processing step.
            var expressionVisitor = new QueryExpressionVisitor(_methodProcessor);

            expression = expressionVisitor.Visit(expression);

            // Get the untyped (typeof object) result from the expression. This does not execute the query
            // in the general case but only builds the 'query-processor' that provides on of possible results:
            // 1. A constant expression of type TranslatedQueryable when the query could be translated to be database
            //    compatible entirely.
            // 2. An IAsyncQueryable<TElement> when the query could not be translated to be database compatible entirely
            //    and includes an in-memory post-processing step.
            // 3. A Task<TResult> / ValueTask<TResult> or another awaitable type that produces a result of type TResult
            //    when a query method is executed as the last step that produces a scalar result
            var untypedResult = expression.Evaluate(); // TODO: Make preferInterpretation param configurable

            if (expression.Type == typeof(TranslatedGroupByQueryable))
            {
                if (untypedResult is not TranslatedGroupByQueryable translatedQueryable)
                {
                    throw new InvalidOperationException(); // TODO
                }

                var elementType = translatedQueryable.ElementType;
                var keyType     = translatedQueryable.KeyType;

                var expectedResultType = TypeHelper.GetAsyncEnumerableType(translatedQueryable.AsyncGroupingType);

                // Due to the check above and the fact that we only translate instances of type AsyncQueryable,
                // the type of the original expression must be one of the following:
                // object,
                // IAsyncQueryable, IAsyncQueryable<T>,
                // IOrderedAsyncQueryable, IOrderedAsyncQueryable<T>,
                // IAsyncEnumerable<T>
                // Therefore TResult MUST be of type IAsyncEnumerable<T>
                if (!typeof(TResult).IsAssignableTo(expectedResultType)) // TODO: Isn't IsAssignableFrom correct here?
                {
                    throw new InvalidOperationException();               // TODO
                }

                // Get the queryable from the expression
                var queryable = translatedQueryable.QueryProvider.CreateQuery(translatedQueryable.Expression);

                // Evaluation the expression
                var result = QueryAdapter.EvaluateAsync(translatedQueryable.GroupingType, queryable, token);

                // Translate IAsyncEnumerable<IGrouping<TKey, TElement>>
                // to IAsyncEnumerable<IAsyncGrouping<TKey, TElement>>
                return((TResult)GroupSequenceConverter.Convert(keyType, elementType, result));
            }

            if (expression.Type == typeof(TranslatedQueryable))
            {
                if (untypedResult is not TranslatedQueryable translatedQueryable)
                {
                    throw new InvalidOperationException(); // TODO
                }

                var elementType = translatedQueryable.ElementType;

                // Due to the check above and the fact that we only translate instances of type AsyncQueryable,
                // the type of the original expression must be one of the following:
                // object,
                // IAsyncQueryable, IAsyncQueryable<T>,
                // IOrderedAsyncQueryable, IOrderedAsyncQueryable<T>,
                // IAsyncEnumerable<T>
                // Therefore TResult MUST be of type IAsyncEnumerable<T>
                if (!typeof(TResult).IsAssignableTo(typeof(IAsyncEnumerable <>).MakeGenericType(elementType))) // TODO: Isn't IsAssignableFrom correct here?
                {
                    throw new InvalidOperationException();                                                     // TODO
                }

                // Get the queryable from the expression
                var queryable = translatedQueryable.QueryProvider.CreateQuery(translatedQueryable.Expression);

                return((TResult)QueryAdapter.EvaluateAsync(elementType, queryable, token));
            }

            // Unpack the result
            if (expressionTypeDescriptor.IsAwaitable && untypedResult is not null)
            {
                untypedResult = await expressionTypeDescriptor.GetAwaitable(untypedResult);
            }

            if (untypedResult is null)
            {
                // TODO: What do we return if the types don't match? Throw an exception?
                //       Is the type annotation of this method even correct?
                return(default !);
Ejemplo n.º 9
0
        public static AsyncTypeAwaitable AsTypeAwaitable <TSource>(this ValueTask <TSource> task)
        {
            var taskTypeDescritor = AwaitableTypeDescriptor.GetTypeDescriptor(task.GetType());

            return(taskTypeDescritor.GetAwaitable(task));
        }
 internal AsyncTypeAwaitable(AwaitableTypeDescriptor awaitableTypeDescriptor, object instance)
 {
     Debug.Assert(awaitableTypeDescriptor.Type.IsAssignableFrom(instance.GetType()));
     _awaitableTypeDescriptor = awaitableTypeDescriptor;
     Instance = instance;
 }