/// <summary> /// General verifier for codefixes. /// Creates a Document from the source string, then gets diagnostics on it and applies the relevant codefixes. /// Then gets the string after the codefix is applied and compares it with the expected result. /// Note: If any codefix causes new diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true. /// </summary> /// <param name="analyzer">The analyzer to be applied to the source code</param> /// <param name="codeFixProvider">The codefix to be applied to the code wherever the relevant Diagnostic is found</param> /// <param name="oldSource">A class in the form of a string before the CodeFix was applied to it</param> /// <param name="newSource">A class in the form of a string after the CodeFix was applied to it</param> private void VerifyFix(TAnalyzer analyzer, TCodeFix codeFixProvider, string oldSource, string newSource) { var document = GetDocument(); var analyzerDiagnostics = GetSortedDiagnosticsFromDocument(analyzer, document); var compilerDiagnostics = GetCompilerDiagnostics(document); var attempts = analyzerDiagnostics.Length; for (int i = 0; i < attempts; ++i) { var actions = new List <CodeAction>(); var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None); codeFixProvider.RegisterCodeFixesAsync(context).Wait(); if (!actions.Any()) { break; } document = ApplyFix(document, actions.ElementAt(0)); analyzerDiagnostics = GetSortedDiagnosticsFromDocument(analyzer, document); //check if there are analyzer diagnostics left after the code fix if (!analyzerDiagnostics.Any()) { break; } } //after applying all of the code fixes, compare the resulting string to the inputted one var actual = GetStringFromDocument(document); Assert.Equal(newSource, actual); Document ApplyFix(Document document, CodeAction codeAction) { var operations = codeAction.GetOperationsAsync(CancellationToken.None).Result; var solution = operations.OfType <ApplyChangesOperation>().Single().ChangedSolution; return(solution.GetDocument(document.Id)); } string GetStringFromDocument(Document document) { var simplifiedDoc = Simplifier.ReduceAsync(document, Simplifier.Annotation).Result; var root = simplifiedDoc.GetSyntaxRootAsync().Result; root = Formatter.Format(root, Formatter.Annotation, simplifiedDoc.Project.Solution.Workspace); return(root.GetText().ToString()); } IEnumerable <Diagnostic> GetCompilerDiagnostics(Document document) { return(document.GetSemanticModelAsync().Result.GetDiagnostics()); } }
public void Run() { var analyzer = new TAnalyzer(); var fix = new TCodeFix(); var actualResults = GetSortedDiagnostics(analyzer); VerifyDiagnosticResults(actualResults, analyzer, ExpectedDiagnostics.ToArray()); if (FixedCode != null) { VerifyFix(analyzer, fix, TestCode, FixedCode); } }
/// <summary> /// Verifies that <paramref name="code"/> produces no diagnostics when analyzed with <typeparamref name="TAnalyzer"/>. /// </summary> /// <typeparam name="TAnalyzer">The type of the analyzer.</typeparam> /// <param name="code">The code to analyze.</param> public static void Valid <TAnalyzer>(params string[] code) where TAnalyzer : DiagnosticAnalyzer, new() { var analyzer = new TAnalyzer(); ValidAsync( analyzer, code, CodeFactory.DefaultCompilationOptions(analyzer, SuppressedDiagnostics), MetadataReferences) .GetAwaiter() .GetResult(); }
private Diagnostic[] GetSortedDiagnosticsFromDocument(TAnalyzer analyzer, Document document) { var diagnostics = new List <Diagnostic>(); var compilation = document.Project.GetCompilationAsync().Result; var options = new AnalyzerOptions(AdditionalFiles.ToImmutableArray <AdditionalText>()); var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create <DiagnosticAnalyzer>(analyzer), options); var diags = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result; diagnostics.AddRange(diags.Concat(compilation.GetDiagnostics().Where(x => x.Severity == DiagnosticSeverity.Error))); var results = SortDiagnostics(diagnostics); diagnostics.Clear(); return(results); }
/// <summary> /// Verifies that <paramref name="codeWithErrorsIndicated"/> produces the expected diagnostics. /// </summary> /// <typeparam name="TAnalyzer">The type of the analyzer.</typeparam> /// <param name="codeWithErrorsIndicated">The code with error positions indicated.</param> public static void Diagnostics <TAnalyzer>(params string[] codeWithErrorsIndicated) where TAnalyzer : DiagnosticAnalyzer, new() { var analyzer = new TAnalyzer(); DiagnosticsWithMetadataAsync( analyzer, DiagnosticsAndSources.CreateFromCodeWithErrorsIndicated(analyzer, codeWithErrorsIndicated), CodeFactory.DefaultCompilationOptions(analyzer, SuppressedDiagnostics), MetadataReferences, null) .GetAwaiter() .GetResult(); }
/// <summary> /// Verifies that /// 1. <paramref name="codeWithErrorsIndicated"/> produces the expected diagnostics /// 2. The code fix does not change the code. /// </summary> /// <typeparam name="TAnalyzer">The type of the analyzer.</typeparam> /// <typeparam name="TCodeFix">The type of the code fix.</typeparam> /// <param name="codeWithErrorsIndicated">The code with error positions indicated.</param> public static void NoFix <TAnalyzer, TCodeFix>(params string[] codeWithErrorsIndicated) where TAnalyzer : DiagnosticAnalyzer, new() where TCodeFix : CodeFixProvider, new() { var analyzer = new TAnalyzer(); NoFixAsync( analyzer, new TCodeFix(), DiagnosticsAndSources.CreateFromCodeWithErrorsIndicated(analyzer, codeWithErrorsIndicated), CodeFactory.DefaultCompilationOptions(analyzer, SuppressedDiagnostics), MetadataReferences) .GetAwaiter() .GetResult(); }
/// <summary> /// Given classes in the form of strings, their language, and an IDiagnosticAnalyzer to apply to it, return the diagnostics found in the string after converting it to a document. /// </summary> /// <param name="analyzer">The analyzer to be run on the sources</param> /// <returns>An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location</returns> private Diagnostic[] GetSortedDiagnostics(TAnalyzer analyzer) { return(GetSortedDiagnosticsFromDocument(analyzer, GetDocument())); }