/// <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="language">The language the source code is in</param>
        /// <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>
        /// <param name="codeFixIndex">Index determining which codefix to apply if there are multiple</param>
        /// <param name="allowNewCompilerDiagnostics">A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied</param>
        private async Task VerifyFixAsync(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, int?codeFixIndex, bool allowNewCompilerDiagnostics)
        {
            var document            = VerificationHelper.CreateDocument(oldSource, language);
            var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzer, new[] { document }).ConfigureAwait(false);

            var compilerDiagnostics = await VerificationHelper.GetCompilerDiagnosticsAsync(document).ConfigureAwait(false);

            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);
                await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);

                if (!actions.Any())
                {
                    break;
                }

                if (codeFixIndex != null)
                {
                    document = await VerificationHelper.ApplyCodeActionAsync(document, actions.ElementAt((int)codeFixIndex)).ConfigureAwait(false);

                    break;
                }

                document = await VerificationHelper.ApplyCodeActionAsync(document, actions.ElementAt(0)).ConfigureAwait(false);

                analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzer, new[] { document }).ConfigureAwait(false);

                var newCompilerDiagnostics = VerificationHelper.GetNewDiagnostics(compilerDiagnostics, await VerificationHelper.GetCompilerDiagnosticsAsync(document).ConfigureAwait(false));

                //check if applying the code fix introduced any new compiler diagnostics
                if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any())
                {
                    // Format and get the compiler diagnostics again so that the locations make sense in the output
                    document = document.WithSyntaxRoot(Formatter.Format(await document.GetSyntaxRootAsync().ConfigureAwait(false),
                                                                        Formatter.Annotation, document.Project.Solution.Workspace));
                    newCompilerDiagnostics = VerificationHelper.GetNewDiagnostics(compilerDiagnostics, await VerificationHelper.GetCompilerDiagnosticsAsync(document).ConfigureAwait(false));

                    Assert.True(false,
                                string.Format("Fix introduced new compiler diagnostics:\r\n{0}\r\n\r\nNew document:\r\n{1}\r\n",
                                              string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString())),
                                              (await document.GetSyntaxRootAsync().ConfigureAwait(false)).ToFullString()));
                }

                //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 = await VerificationHelper.GetStringFromDocumentAsync(document).ConfigureAwait(false);

            Assert.Equal(newSource, actual);
        }
        /// <summary>
        /// General verifier for refactorings.
        /// Creates a Document from the source string, then applies the relevant refactorings.
        /// Then gets the string after the refactoring is applied and compares it with the expected result.
        /// Note: If any refactoring causes new compiler diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true.
        /// </summary>
        /// <param name="language">The language the source code is in</param>
        /// <param name="codeRefactoringProvider">The refactoring to be applied to the code</param>
        /// <param name="oldSource">A class in the form of a string before the refactoring was applied to it</param>
        /// <param name="newSource">A class in the form of a string after the refactoring was applied to it</param>
        /// <param name="nodeToRefactor">A function that finds selected node for refactoring accepting the root node as an argument</param>
        /// <param name="codeRefactoringIndex">Index determining which refactoring to apply if there are multiple</param>
        /// <param name="allowNewCompilerDiagnostics">A bool controlling whether or not the test will fail if the refactoring introduces other warnings after being applied</param>
        private async Task VerifyRefactoringAsync(string language, CodeRefactoringProvider codeRefactoringProvider,
                                                  string oldSource, string newSource, Func <SyntaxNode, SyntaxNode> nodeToRefactor,
                                                  int?codeRefactoringIndex, bool allowNewCompilerDiagnostics)
        {
            var document            = VerificationHelper.CreateDocument(oldSource, language);
            var compilerDiagnostics = (await VerificationHelper.GetCompilerDiagnosticsAsync(document).ConfigureAwait(false)).ToArray();

            var actions = new List <CodeAction>();
            var root    = await document.GetSyntaxRootAsync().ConfigureAwait(false);

            var node    = nodeToRefactor(root);
            var context = new CodeRefactoringContext(document, node.FullSpan, a => actions.Add(a),
                                                     CancellationToken.None);

            await codeRefactoringProvider.ComputeRefactoringsAsync(context).ConfigureAwait(false);

            if (actions.Count > 0)
            {
                document = await VerificationHelper.ApplyCodeActionAsync(document, codeRefactoringIndex != null
                                                                         ?actions[(int)codeRefactoringIndex]
                                                                         : actions[0]).ConfigureAwait(false);

                var newCompilerDiagnostics = VerificationHelper.GetNewDiagnostics(compilerDiagnostics,
                                                                                  await VerificationHelper.GetCompilerDiagnosticsAsync(document).ConfigureAwait(false));

                //check if applying the code fix introduced any new compiler diagnostics
                if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any())
                {
                    // Format and get the compiler diagnostics again so that the locations make sense in the output
                    document = document.WithSyntaxRoot(Formatter.Format(await document.GetSyntaxRootAsync().ConfigureAwait(false),
                                                                        Formatter.Annotation, document.Project.Solution.Workspace));
                    newCompilerDiagnostics = VerificationHelper.GetNewDiagnostics(compilerDiagnostics,
                                                                                  await VerificationHelper.GetCompilerDiagnosticsAsync(document).ConfigureAwait(false));

                    var newSyntaxRoot = await document.GetSyntaxRootAsync().ConfigureAwait(false);

                    Assert.True(false,
                                string.Format("Refactoring introduced new compiler diagnostics:\r\n{0}\r\n\r\nNew document:\r\n{1}\r\n",
                                              string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString())), newSyntaxRoot.ToFullString()));
                }
            }

            //after applying all of the refactorings, compare the resulting string to the inputted one
            var actual = await VerificationHelper.GetStringFromDocumentAsync(document).ConfigureAwait(false);

            Assert.Equal(newSource, actual);
        }