AsyncEnumerableNamingTests.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. using Xunit;
  10. namespace Tests
  11. {
  12. public class AsyncEnumerableNamingTests
  13. {
  14. [Fact]
  15. public static void AsyncEnumerable_MethodNames()
  16. {
  17. var methods = typeof(AsyncEnumerable).GetMethods(BindingFlags.Public | BindingFlags.Static);
  18. //
  19. // Async suffix
  20. //
  21. var asyncMethodsNoAsyncSuffix = (from m in methods
  22. where IsTaskLike(m.ReturnType)
  23. where !m.Name.EndsWith("Async")
  24. select m.Name)
  25. .ToArray();
  26. Assert.Empty(asyncMethodsNoAsyncSuffix);
  27. //
  28. // Consistency of delegate types and Await[WithCancellation] naming convention
  29. //
  30. var methodsWithDelegateParameter = (from m in methods
  31. where m.GetParameters().Any(p => IsAsyncDelegate(p.ParameterType))
  32. select m)
  33. .ToArray();
  34. foreach (var m in methodsWithDelegateParameter)
  35. {
  36. var kinds = (from p in m.GetParameters()
  37. where IsDelegate(p.ParameterType)
  38. select GetDelegateKind(p.ParameterType))
  39. .Distinct();
  40. Assert.Single(kinds);
  41. var suffix = IsTaskLike(m.ReturnType) ? "Async" : "";
  42. switch (kinds.Single())
  43. {
  44. case DelegateKind.Async:
  45. suffix = "Await" + suffix;
  46. break;
  47. case DelegateKind.AsyncCancel:
  48. suffix = "AwaitWithCancellation" + suffix;
  49. break;
  50. }
  51. Assert.EndsWith(suffix, m.Name);
  52. }
  53. static bool IsValueTask(Type t) => t == typeof(ValueTask) || (t.IsConstructedGenericType && t.GetGenericTypeDefinition() == typeof(ValueTask<>));
  54. static bool IsTask(Type t) => typeof(Task).IsAssignableFrom(t);
  55. static bool IsTaskLike(Type t) => IsTask(t) || IsValueTask(t);
  56. static bool IsDelegate(Type t) => typeof(Delegate).IsAssignableFrom(t);
  57. static bool TryGetInvoke(Type t, out MethodInfo m) => (m = t.GetMethod("Invoke")) != null;
  58. static bool IsAsyncDelegate(Type t) => IsDelegate(t) && TryGetInvoke(t, out var i) && IsTaskLike(i.ReturnType);
  59. static bool IsCancelableDelegate(Type t) => IsDelegate(t) && TryGetInvoke(t, out var i) && i.GetParameters().LastOrDefault()?.ParameterType == typeof(CancellationToken);
  60. static DelegateKind GetDelegateKind(Type t) => IsAsyncDelegate(t) ? (IsCancelableDelegate(t) ? DelegateKind.AsyncCancel : DelegateKind.Async) : DelegateKind.Sync;
  61. }
  62. private enum DelegateKind
  63. {
  64. Sync,
  65. Async,
  66. AsyncCancel,
  67. }
  68. }
  69. }