TestExtensionMethodAnalyzerBase.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Reactive.Analyzers.Test.Verifiers;
  5. using Microsoft.CodeAnalysis.Testing;
  6. namespace System.Reactive.Analyzers.Test
  7. {
  8. #pragma warning disable CA1052 // Static holder types should be Static or NotInheritable - we do in fact derive from this,
  9. public class TestExtensionMethodAnalyzerBase
  10. #pragma warning restore CA1052
  11. {
  12. protected enum DiagnosticTarget
  13. {
  14. Argument,
  15. MethodName
  16. }
  17. protected static async Task TestExtensionMethod(
  18. string source,
  19. string? targetType,
  20. string extensionMethodName,
  21. string diagnosticId,
  22. string diagnosticArgument,
  23. string? additionalArguments,
  24. DiagnosticTarget diagnosticTarget,
  25. string? expectedOriginalError = null)
  26. {
  27. // targetType is null when invoking a method that does not take a target argument.
  28. string target = targetType is null
  29. ? ""
  30. : "target";
  31. // Some diagnostics apply to the argument, and some to the method name.
  32. string invocation = diagnosticTarget switch
  33. {
  34. DiagnosticTarget.Argument => $$""".{{extensionMethodName}}({|#0:{{target}}|}{{additionalArguments}})""",
  35. DiagnosticTarget.MethodName => $$""".{|#0:{{extensionMethodName}}|}({{target}}{{additionalArguments}})""",
  36. _ => throw new ArgumentOutOfRangeException(nameof(diagnosticTarget))
  37. };
  38. string? targetDeclaration = targetType is null
  39. ? null
  40. : $"{targetType} target = default!;";
  41. var test = $$"""
  42. using System;
  43. using System.Reactive.Linq;
  44. {{targetDeclaration}}
  45. {{source}}
  46. {{invocation}}
  47. .Subscribe(Console.WriteLine);
  48. """;
  49. expectedOriginalError ??= additionalArguments is null
  50. ? "CS1503" // single-argument overloads
  51. : "CS1501"; // multi-argument overloads
  52. var normalError = new DiagnosticResult(expectedOriginalError, Microsoft.CodeAnalysis.DiagnosticSeverity.Error)
  53. .WithLocation(0);
  54. var customDiagnostic = AddUiFrameworkPackageAnalyzerVerifier.Diagnostic(diagnosticId)
  55. .WithLocation(0)
  56. .WithArguments(diagnosticArgument, "extension method");
  57. await AddUiFrameworkPackageAnalyzerVerifier.VerifyAnalyzerAsync(
  58. test,
  59. normalError,
  60. customDiagnostic);
  61. }
  62. protected static Task TestExtensionMethodOnIObservable(
  63. string targetDeclaration,
  64. string extensionMethodName,
  65. string diagnosticId)
  66. {
  67. return TestExtensionMethod(
  68. "Observable.Interval(TimeSpan.FromSeconds(0.5))",
  69. targetDeclaration,
  70. extensionMethodName,
  71. diagnosticId,
  72. extensionMethodName,
  73. additionalArguments: null,
  74. diagnosticTarget: DiagnosticTarget.Argument);
  75. }
  76. protected static Task TestExtensionMethodOnIObservable(
  77. string? targetType,
  78. string extensionMethodName,
  79. string diagnosticId,
  80. string diagnosticArgument,
  81. string? additionalArguments = null,
  82. string? expectedOriginalError = null,
  83. DiagnosticTarget? diagnosticTarget = null)
  84. {
  85. return TestExtensionMethod(
  86. "Observable.Interval(TimeSpan.FromSeconds(0.5))",
  87. targetType,
  88. extensionMethodName,
  89. diagnosticId,
  90. diagnosticArgument,
  91. additionalArguments,
  92. diagnosticTarget: diagnosticTarget ?? (additionalArguments is null ? DiagnosticTarget.Argument : DiagnosticTarget.MethodName),
  93. expectedOriginalError: expectedOriginalError);
  94. }
  95. protected static Task TestExtensionMethodOnIObservableNoArguments(
  96. string? targetType,
  97. string extensionMethodName,
  98. string diagnosticId)
  99. {
  100. return TestExtensionMethod(
  101. "Observable.Interval(TimeSpan.FromSeconds(0.5))",
  102. targetType,
  103. extensionMethodName,
  104. diagnosticId,
  105. $"{extensionMethodName}()",
  106. additionalArguments: null,
  107. expectedOriginalError: "CS1061",
  108. diagnosticTarget: DiagnosticTarget.MethodName);
  109. }
  110. protected static Task TestExtensionMethodOnSubject(
  111. string targetDeclaration,
  112. string extensionMethodName,
  113. string diagnosticId)
  114. {
  115. return TestExtensionMethod(
  116. "new System.Reactive.Subjects.Subject<int>()",
  117. targetDeclaration,
  118. extensionMethodName,
  119. diagnosticId,
  120. extensionMethodName,
  121. additionalArguments: null,
  122. diagnosticTarget: DiagnosticTarget.Argument);
  123. }
  124. protected static Task TestExtensionMethodOnSubject(
  125. string targetDeclaration,
  126. string extensionMethodName,
  127. string diagnosticId,
  128. string diagnosticArgument)
  129. {
  130. return TestExtensionMethod(
  131. "new System.Reactive.Subjects.Subject<int>()",
  132. targetDeclaration,
  133. extensionMethodName,
  134. diagnosticId,
  135. diagnosticArgument,
  136. additionalArguments: null,
  137. diagnosticTarget: DiagnosticTarget.Argument);
  138. }
  139. }
  140. }