/// <summary> /// Verifies that <paramref name="sources"/> produces the expected diagnostics. /// </summary> /// <param name="analyzer">The analyzer to apply.</param> /// <param name="sources">The code with error positions indicated.</param> /// <param name="compilationOptions">The <see cref="CSharpCompilationOptions"/> to use.</param> /// <param name="metadataReferences">The meta data metadataReferences to use when compiling.</param> /// <param name="expectedMessage">The expected message in the diagnostic produced by the analyzer.</param> /// <returns>The meta data from the run..</returns> public static async Task <DiagnosticsMetadata> DiagnosticsWithMetadataAsync( DiagnosticAnalyzer analyzer, DiagnosticsAndSources sources, CSharpCompilationOptions compilationOptions, IReadOnlyList <MetadataReference> metadataReferences, string expectedMessage = null) { if (sources.ExpectedDiagnostics.Count == 0) { throw AssertException.Create("Expected code to have at least one error position indicated with '↓'"); } var data = await Analyze.GetDiagnosticsWithMetadataAsync( analyzer, sources.Code, compilationOptions, metadataReferences) .ConfigureAwait(false); var expecteds = sources.ExpectedDiagnostics; var actuals = data.Diagnostics .SelectMany(x => x) .ToArray(); if (expecteds.SetEquals(actuals)) { if (expectedMessage != null) { foreach (var actual in data.Diagnostics.SelectMany(x => x)) { var actualMessage = actual.GetMessage(CultureInfo.InvariantCulture); TextAssert.AreEqual(expectedMessage, actualMessage, $"Expected and actual diagnostic message for the diagnostic {actual} does not match"); } } return(new DiagnosticsMetadata( sources.Code, sources.ExpectedDiagnostics, data.Diagnostics, data.Solution)); } var error = StringBuilderPool.Borrow(); error.AppendLine("Expected and actual diagnostics do not match."); var missingExpected = expecteds.Except(actuals); for (var i = 0; i < missingExpected.Count; i++) { if (i == 0) { error.Append("Expected:\r\n"); } var expected = missingExpected[i]; error.AppendLine(expected.ToString(sources.Code)); } if (actuals.Length == 0) { error.AppendLine("Actual: <no errors>"); } var missingActual = actuals.Except(expecteds); if (actuals.Length > 0 && missingActual.Count == 0) { error.AppendLine("Actual: <missing>"); } for (var i = 0; i < missingActual.Count; i++) { if (i == 0) { error.Append("Actual:\r\n"); } var actual = missingActual[i]; error.AppendLine(actual.ToString(sources.Code)); } throw AssertException.Create(StringBuilderPool.Return(error)); }
private static void VerifyDiagnostics(DiagnosticsAndSources diagnosticsAndSources, IReadOnlyList <ImmutableArray <Diagnostic> > diagnostics, Solution solution, string?expectedMessage = null) { if (diagnosticsAndSources.ExpectedDiagnostics.Count == 0) { throw new AssertException("Expected code to have at least one error position indicated with '↓'"); } var allDiagnostics = diagnostics.SelectMany(x => x).ToArray(); if (allDiagnostics.Length == 0) { allDiagnostics = Analyze.GetDiagnostics(solution).SelectMany(x => x).ToArray(); } if (Equals()) { if (expectedMessage != null) { foreach (var actual in allDiagnostics) { var actualMessage = actual.GetMessage(CultureInfo.InvariantCulture); TextAssert.AreEqual(expectedMessage, actualMessage, $"Expected and actual diagnostic message for the diagnostic {actual} does not match"); } } return; } var error = StringBuilderPool.Borrow(); if (allDiagnostics.Length == 1 && diagnosticsAndSources.ExpectedDiagnostics.Count == 1 && diagnosticsAndSources.ExpectedDiagnostics[0].Id == allDiagnostics[0].Id) { if (diagnosticsAndSources.ExpectedDiagnostics[0].PositionMatches(allDiagnostics[0]) && !diagnosticsAndSources.ExpectedDiagnostics[0].MessageMatches(allDiagnostics[0])) { CodeAssert.AreEqual(diagnosticsAndSources.ExpectedDiagnostics[0].Message !, allDiagnostics[0].GetMessage(CultureInfo.InvariantCulture), "Expected and actual messages do not match."); } } error.AppendLine("Expected and actual diagnostics do not match.") .AppendLine("Expected:"); foreach (var expected in diagnosticsAndSources.ExpectedDiagnostics.OrderBy(x => x.Span.StartLinePosition)) { error.AppendLine(expected.ToString(diagnosticsAndSources.Code, " ")); } if (allDiagnostics.Length == 0) { error.AppendLine("Actual: <no diagnostics>"); } else { error.AppendLine("Actual:"); foreach (var diagnostic in allDiagnostics.OrderBy(x => x.Location.SourceSpan.Start)) { error.AppendLine(diagnostic.ToErrorString(" ")); } } throw new AssertException(error.Return()); bool Equals() { foreach (var diagnostic in allDiagnostics) { if (diagnosticsAndSources.ExpectedDiagnostics.Any(e => e.Matches(diagnostic))) { continue; } return(false); } foreach (var expected in diagnosticsAndSources.ExpectedDiagnostics) { if (allDiagnostics.Any(a => expected.Matches(a))) { continue; } return(false); } return(true); } }
private static void VerifyDiagnostics(DiagnosticsAndSources diagnosticsAndSources, IReadOnlyList <Diagnostic> actuals, string expectedMessage = null) { if (diagnosticsAndSources.ExpectedDiagnostics.Count == 0) { throw new AssertException("Expected code to have at least one error position indicated with '↓'"); } if (diagnosticsAndSources.ExpectedDiagnostics.SetEquals(actuals)) { if (expectedMessage != null) { foreach (var actual in actuals) { var actualMessage = actual.GetMessage(CultureInfo.InvariantCulture); TextAssert.AreEqual(expectedMessage, actualMessage, $"Expected and actual diagnostic message for the diagnostic {actual} does not match"); } } return; } var error = StringBuilderPool.Borrow(); if (actuals.Count == 1 && diagnosticsAndSources.ExpectedDiagnostics.Count == 1 && diagnosticsAndSources.ExpectedDiagnostics[0].Id == actuals[0].Id) { if (diagnosticsAndSources.ExpectedDiagnostics[0].PositionMatches(actuals[0]) && !diagnosticsAndSources.ExpectedDiagnostics[0].MessageMatches(actuals[0])) { CodeAssert.AreEqual(diagnosticsAndSources.ExpectedDiagnostics[0].Message, actuals[0].GetMessage(CultureInfo.InvariantCulture), "Expected and actual messages do not match."); } } error.AppendLine("Expected and actual diagnostics do not match."); var missingExpected = diagnosticsAndSources.ExpectedDiagnostics.Except(actuals); for (var i = 0; i < missingExpected.Count; i++) { if (i == 0) { error.Append("Expected:\r\n"); } var expected = missingExpected[i]; error.AppendLine(expected.ToString(diagnosticsAndSources.Code)); } if (actuals.Count == 0) { error.AppendLine("Actual: <no errors>"); } var missingActual = actuals.Except(diagnosticsAndSources.ExpectedDiagnostics); if (actuals.Count > 0 && missingActual.Count == 0) { error.AppendLine("Actual: <missing>"); } for (var i = 0; i < missingActual.Count; i++) { if (i == 0) { error.Append("Actual:\r\n"); } var actual = missingActual[i]; error.AppendLine(actual.ToErrorString()); } throw new AssertException(error.Return()); }