| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 | // Licensed to the .NET Foundation under one or more agreements.// The .NET Foundation licenses this file to you under the Apache 2.0 License.// See the LICENSE file in the project root for more information. using System;using System.Linq;using System.Reflection;using System.Threading;using System.Threading.Tasks;using Xunit;namespace Tests{    public class AsyncEnumerableNamingTests    {        [Fact]        public static void AsyncEnumerable_MethodNames()        {            var methods = typeof(AsyncEnumerable).GetMethods(BindingFlags.Public | BindingFlags.Static);            //            // Async suffix            //            var asyncMethodsNoAsyncSuffix = (from m in methods                                             where IsTaskLike(m.ReturnType)                                             where !m.Name.EndsWith("Async")                                             select m.Name)                                            .ToArray();            Assert.Empty(asyncMethodsNoAsyncSuffix);            //            // Consistency of delegate types and Await[WithCancellation] naming convention            //            var methodsWithDelegateParameter = (from m in methods                                                where m.GetParameters().Any(p => IsAsyncDelegate(p.ParameterType))                                                select m)                                               .ToArray();            foreach (var m in methodsWithDelegateParameter)            {                var kinds = (from p in m.GetParameters()                             where IsDelegate(p.ParameterType)                             select GetDelegateKind(p.ParameterType))                            .Distinct();                Assert.Single(kinds);                var suffix = IsTaskLike(m.ReturnType) ? "Async" : "";                switch (kinds.Single())                {                    case DelegateKind.Async:                        suffix = "Await" + suffix;                        break;                    case DelegateKind.AsyncCancel:                        suffix = "AwaitWithCancellation" + suffix;                        break;                }                Assert.EndsWith(suffix, m.Name);            }            static bool IsValueTask(Type t) => t == typeof(ValueTask) || (t.IsConstructedGenericType && t.GetGenericTypeDefinition() == typeof(ValueTask<>));            static bool IsTask(Type t) => typeof(Task).IsAssignableFrom(t);            static bool IsTaskLike(Type t) => IsTask(t) || IsValueTask(t);            static bool IsDelegate(Type t) => typeof(Delegate).IsAssignableFrom(t);            static bool TryGetInvoke(Type t, out MethodInfo m) => (m = t.GetMethod("Invoke")) != null;            static bool IsAsyncDelegate(Type t) => IsDelegate(t) && TryGetInvoke(t, out var i) && IsTaskLike(i.ReturnType);            static bool IsCancelableDelegate(Type t) => IsDelegate(t) && TryGetInvoke(t, out var i) && i.GetParameters().LastOrDefault()?.ParameterType == typeof(CancellationToken);            static DelegateKind GetDelegateKind(Type t) => IsAsyncDelegate(t) ? (IsCancelableDelegate(t) ? DelegateKind.AsyncCancel : DelegateKind.Async) : DelegateKind.Sync;        }        private enum DelegateKind        {            Sync,            Async,            AsyncCancel,        }    }}
 |