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 !);
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; }