private static bool HasAnyContentChanges(bool willInherit, SolutionState state, SolutionState baseState) { if (state == null) { throw new ArgumentNullException(nameof(state)); } if (baseState == null) { throw new ArgumentNullException(nameof(baseState)); } if ((!willInherit || state.Sources.Any()) && !ContentEqual(state.Sources, baseState.Sources)) { return(true); } if ((!willInherit || state.GeneratedSources.Any()) && !ContentEqual(state.GeneratedSources, baseState.GeneratedSources)) { return(true); } if ((!willInherit || state.AdditionalFiles.Any()) && !ContentEqual(state.AdditionalFiles, baseState.AdditionalFiles)) { return(true); } if ((!willInherit || state.AnalyzerConfigFiles.Any()) && !ContentEqual(state.AnalyzerConfigFiles, baseState.AnalyzerConfigFiles)) { return(true); } if ((!willInherit || state.AdditionalReferences.Any()) && !state.AdditionalReferences.SequenceEqual(baseState.AdditionalReferences)) { return(true); } return(false); }
/// <summary> /// Called to test a C# source generator when applied on the input source as a string. /// </summary> /// <param name="testState">The effective input test state.</param> /// <param name="fixedState">The effective test state after the source generators are applied.</param> /// <param name="verifier">The verifier to use for test assertions.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that the task will observe.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> protected async Task <ImmutableArray <Diagnostic> > VerifySourceGeneratorAsync(SolutionState testState, SolutionState fixedState, IVerifier verifier, CancellationToken cancellationToken) { return(await VerifySourceGeneratorAsync(Language, GetSourceGenerators().ToImmutableArray(), testState, fixedState, ApplySourceGeneratorAsync, verifier.PushContext("Source generator application"), cancellationToken)); }
private async Task <ImmutableArray <Diagnostic> > VerifySourceGeneratorAsync( string language, ImmutableArray <ISourceGenerator> sourceGenerators, SolutionState oldState, SolutionState newState, Func <ImmutableArray <ISourceGenerator>, Project, IVerifier, CancellationToken, Task <(Project project, ImmutableArray <Diagnostic> diagnostics)> > getFixedProject,
private static bool HasAnyChange(SolutionState oldState, SolutionState newState) { return(!oldState.Sources.SequenceEqual(newState.Sources, SourceFileEqualityComparer.Instance) || !oldState.AdditionalFiles.SequenceEqual(newState.AdditionalFiles, SourceFileEqualityComparer.Instance)); }
/// <summary> /// Called to test a C# code fix when applied on the input source as a string. /// </summary> /// <param name="testState">The effective input test state.</param> /// <param name="fixedState">The effective test state after incremental code fixes are applied.</param> /// <param name="batchFixedState">The effective test state after batch code fixes are applied.</param> /// <param name="verifier">The verifier to use for test assertions.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that the task will observe.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> protected async Task VerifyFixAsync(SolutionState testState, SolutionState fixedState, SolutionState batchFixedState, IVerifier verifier, CancellationToken cancellationToken) { int numberOfIncrementalIterations; int numberOfFixAllIterations; int numberOfFixAllInDocumentIterations; if (NumberOfIncrementalIterations != null) { numberOfIncrementalIterations = NumberOfIncrementalIterations.Value; } else { if (!HasAnyChange(testState, fixedState)) { numberOfIncrementalIterations = 0; } else { // Expect at most one iteration per fixable diagnostic var fixers = GetCodeFixProviders().ToArray(); var fixableExpectedDiagnostics = testState.ExpectedDiagnostics.Count(diagnostic => fixers.Any(fixer => fixer.FixableDiagnosticIds.Contains(diagnostic.Id))); numberOfIncrementalIterations = -fixableExpectedDiagnostics; } } if (NumberOfFixAllIterations != null) { numberOfFixAllIterations = NumberOfFixAllIterations.Value; } else { if (!HasAnyChange(testState, batchFixedState)) { numberOfFixAllIterations = 0; } else { numberOfFixAllIterations = 1; } } if (NumberOfFixAllInDocumentIterations != null) { numberOfFixAllInDocumentIterations = NumberOfFixAllInDocumentIterations.Value; } else { numberOfFixAllInDocumentIterations = numberOfFixAllIterations; } var t1 = VerifyFixAsync(Language, GetDiagnosticAnalyzers().ToImmutableArray(), GetCodeFixProviders().ToImmutableArray(), testState, fixedState, numberOfIncrementalIterations, FixEachAnalyzerDiagnosticAsync, verifier.PushContext("Iterative code fix application"), cancellationToken).ConfigureAwait(false); var fixAllProvider = GetCodeFixProviders().Select(codeFixProvider => codeFixProvider.GetFixAllProvider()).Where(codeFixProvider => codeFixProvider != null).ToImmutableArray(); if (fixAllProvider.IsEmpty) { await t1; } else { if (Debugger.IsAttached) { await t1; } var t2 = VerifyFixAsync(Language, GetDiagnosticAnalyzers().ToImmutableArray(), GetCodeFixProviders().ToImmutableArray(), testState, batchFixedState, numberOfFixAllInDocumentIterations, FixAllAnalyzerDiagnosticsInDocumentAsync, verifier.PushContext("Fix all in document"), cancellationToken).ConfigureAwait(false); if (Debugger.IsAttached) { await t2; } var t3 = VerifyFixAsync(Language, GetDiagnosticAnalyzers().ToImmutableArray(), GetCodeFixProviders().ToImmutableArray(), testState, batchFixedState, numberOfFixAllIterations, FixAllAnalyzerDiagnosticsInProjectAsync, verifier.PushContext("Fix all in project"), cancellationToken).ConfigureAwait(false); if (Debugger.IsAttached) { await t3; } var t4 = VerifyFixAsync(Language, GetDiagnosticAnalyzers().ToImmutableArray(), GetCodeFixProviders().ToImmutableArray(), testState, batchFixedState, numberOfFixAllIterations, FixAllAnalyzerDiagnosticsInSolutionAsync, verifier.PushContext("Fix all in solution"), cancellationToken).ConfigureAwait(false); if (Debugger.IsAttached) { await t4; } if (!Debugger.IsAttached) { // Allow the operations to run in parallel await t1; await t2; await t3; await t4; } } }
protected CodeFixTest() { FixedState = new SolutionState(DefaultFilePathPrefix, DefaultFileExt); BatchFixedState = new SolutionState(DefaultFilePathPrefix, DefaultFileExt); }
protected CodeRefactoringTest() { FixedState = new SolutionState(DefaultTestProjectName, Language, DefaultFilePathPrefix, DefaultFileExt); }
/// <summary> /// Applies the <see cref="InheritanceMode"/> using a specified base state. /// </summary> /// <remarks> /// <para>This method evaluates <see cref="ProjectState.AdditionalFilesFactories"/>, and places the resulting /// additional files in the <see cref="ProjectState.AdditionalFiles"/> collection of the result before /// returning.</para> /// </remarks> /// <param name="baseState">The base state to inherit from, or <see langword="null"/> if the current state is /// the root state.</param> /// <param name="fixableDiagnostics">The set of diagnostic IDs to treat as fixable. Fixable diagnostics present /// in the <see cref="ExpectedDiagnostics"/> collection of the base state are only inherited for /// <see cref="StateInheritanceMode.AutoInheritAll"/>.</param> /// <returns>A new <see cref="SolutionState"/> representing the current state with inherited values applied /// where appropriate. The <see cref="InheritanceMode"/> of the result is /// <see cref="StateInheritanceMode.Explicit"/>.</returns> public SolutionState WithInheritedValuesApplied(SolutionState?baseState, ImmutableArray <string> fixableDiagnostics) { var inheritanceMode = InheritanceMode; var markupHandling = MarkupHandling; if (inheritanceMode == null || markupHandling == null) { if (baseState == null) { inheritanceMode = inheritanceMode ?? StateInheritanceMode.Explicit; markupHandling = markupHandling ?? MarkupMode.Allow; } else if (HasAnyContentChanges(willInherit: inheritanceMode != StateInheritanceMode.Explicit, this, baseState)) { inheritanceMode = inheritanceMode ?? StateInheritanceMode.AutoInherit; markupHandling = markupHandling ?? MarkupMode.IgnoreFixable; } else { inheritanceMode = inheritanceMode ?? StateInheritanceMode.AutoInheritAll; markupHandling = markupHandling ?? baseState.MarkupHandling ?? MarkupMode.Allow; } } if (inheritanceMode != StateInheritanceMode.AutoInherit && inheritanceMode != StateInheritanceMode.Explicit && inheritanceMode != StateInheritanceMode.AutoInheritAll) { throw new InvalidOperationException($"Unexpected inheritance mode: {inheritanceMode}"); } if (baseState?.AdditionalFilesFactories.Count > 0) { throw new InvalidOperationException("The base state should already have its inheritance state evaluated prior to its use as a base state."); } var result = new SolutionState(Name, Language, DefaultPrefix, DefaultExtension); result.ReferenceAssemblies = ReferenceAssemblies; result.OutputKind = OutputKind; result.DocumentationMode = DocumentationMode; if (inheritanceMode != StateInheritanceMode.Explicit && baseState != null) { result.ReferenceAssemblies ??= baseState.ReferenceAssemblies; result.OutputKind ??= baseState.OutputKind; result.DocumentationMode ??= baseState.DocumentationMode; if (Sources.Count == 0) { result.Sources.AddRange(baseState.Sources); } if (AdditionalFiles.Count == 0) { result.AdditionalFiles.AddRange(baseState.AdditionalFiles); } if (AnalyzerConfigFiles.Count == 0) { result.AnalyzerConfigFiles.AddRange(baseState.AnalyzerConfigFiles); } if (AdditionalProjects.Count == 0) { result.AdditionalProjects.AddRange(baseState.AdditionalProjects); } if (AdditionalProjectReferences.Count == 0) { result.AdditionalProjectReferences.AddRange(baseState.AdditionalProjectReferences); } if (AdditionalReferences.Count == 0) { result.AdditionalReferences.AddRange(baseState.AdditionalReferences); } if (ExpectedDiagnostics.Count == 0) { if (inheritanceMode == StateInheritanceMode.AutoInherit) { result.ExpectedDiagnostics.AddRange(baseState.ExpectedDiagnostics.Where(diagnostic => !fixableDiagnostics.Contains(diagnostic.Id))); } else { result.ExpectedDiagnostics.AddRange(baseState.ExpectedDiagnostics); } } } result.MarkupHandling = markupHandling; result.InheritanceMode = StateInheritanceMode.Explicit; result.Sources.AddRange(Sources); result.AdditionalFiles.AddRange(AdditionalFiles); result.AnalyzerConfigFiles.AddRange(AnalyzerConfigFiles); result.AdditionalProjects.AddRange(AdditionalProjects); result.AdditionalProjectReferences.AddRange(AdditionalProjectReferences); result.AdditionalReferences.AddRange(AdditionalReferences); result.ExpectedDiagnostics.AddRange(ExpectedDiagnostics); result.AdditionalFiles.AddRange(AdditionalFilesFactories.SelectMany(factory => factory())); return(result); }
protected AnalyzerTest() { TestState = new SolutionState(DefaultFilePathPrefix, DefaultFileExt); }
protected CodeRefactoringTest() { FixedState = new SolutionState(DefaultFilePathPrefix, DefaultFileExt); }