public static void IsWithinOnOneLine(DiagnosticResultLocation expected, Location actual) { var actualSpan = actual.GetLineSpan(); Assert.IsTrue( actualSpan.Path == expected.Path || (actualSpan.Path != null && actualSpan.Path.Contains("Test0.") && expected.Path.Contains("Test.")), $"Expected diagnostic to be in file \"{expected.Path}\" was actually in file \"{actualSpan.Path}\""); var actualLinePosition = actualSpan.StartLinePosition; // Only check line position if there is an actual line in the real diagnostic if (actualLinePosition.Line > 0) { Assert.AreEqual(expected.Line, actualLinePosition.Line + 1, $"Expected diagnostic to be on line \"{expected.Line}\" was actually on line \"{actualLinePosition.Line + 1}\""); } // Only check column position if there is an actual column position in the real diagnostic if (actualLinePosition.Character > 0) { Assert.That( expected.Column <= actualLinePosition.Character + 1, $"Expected diagnostic to start at column greater than \"{expected.Column - 1}\" was actually at column \"{actualLinePosition.Character + 1}\""); } }
public static void DiagnosticLocation(DiagnosticResultLocation expected, Location actual) { var actualSpan = actual.GetLineSpan(); var actualLinePosition = actualSpan.StartLinePosition; // Only check line position if there is an actual line in the real diagnostic if (actualLinePosition.Line > 0) { if (actualLinePosition.Line + 1 != expected.Line) { throw new DiagnosticLocationAssertException( expected, actual, $"Expected diagnostic to be on line \"{expected.Line}\" was actually on line \"{actualLinePosition.Line + 1}\""); } } // Only check column position if there is an actual column position in the real diagnostic if (actualLinePosition.Character > 0) { if (actualLinePosition.Character + 1 != expected.Column) { throw new DiagnosticLocationAssertException( expected, actual, $"Expected diagnostic to start at column \"{expected.Column}\" was actually on line \"{actualLinePosition.Character + 1}\""); } } }
public DiagnosticLocationAssertException( DiagnosticResultLocation expected, Location actual, string message) : base(expected, actual) { Message = message; }
private static string GetNotInExpectedFileMessage(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, DiagnosticResultLocation expected, FileLinePositionSpan actualSpan) { return ($"Expected diagnostic to be in file \"{expected.Path}\" was actually in file \"{actualSpan.Path}\"{Environment.NewLine}{Environment.NewLine}Diagnostic:{Environment.NewLine} {FormatDiagnostics(analyzer, new[] { diagnostic })}{Environment.NewLine}"); }
private static string GetNotInExpectedLineMessage(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, DiagnosticResultLocation expected, LinePosition actualLinePosition) { return ($"Expected diagnostic to be on line \"{expected.Line}\" was actually on line \"{actualLinePosition.Line + 1}\"{Environment.NewLine}{Environment.NewLine}Diagnostic:{Environment.NewLine} {FormatDiagnostics(analyzer, new[] { diagnostic })}{Environment.NewLine}"); }
private static string GetNotInExpectedColumn(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, DiagnosticResultLocation expected, LinePosition actualLinePosition) { return ($"Expected diagnostic to start at column \"{expected.Column}\" was actually at column \"{actualLinePosition.Character + 1}\"{Environment.NewLine}{Environment.NewLine}Diagnostic:{Environment.NewLine} {FormatDiagnostics(analyzer, new[] { diagnostic })}{Environment.NewLine}"); }
public void Initialize_EnumDeclarationWithoutDocumentationHeader_DiagnosticDetected() { // Arrange string expectedMessage = "Element 'TestEnum' should be documented."; var expectedLocation = new DiagnosticResultLocation("Test0.cs", 1, 13); DiagnosticResult expectedResult = this.CreateDiagnosticResult(expectedMessage, expectedLocation); string sourceCode = @"public enum TestEnum { }"; // Act + Assert this.VerifyCSharpDiagnostic(sourceCode, expectedResult); }
/// <summary> /// Helper method to VerifyDiagnosticResult that checks the location of a diagnostic and compares it with the location in /// the expected DiagnosticResult. /// </summary> /// <param name="analyzer">The analyzer that was being run on the sources</param> /// <param name="diagnostic">The diagnostic that was found in the code</param> /// <param name="actual">The Location of the Diagnostic found in the code</param> /// <param name="expected">The DiagnosticResultLocation that should have been found</param> private static void VerifyDiagnosticLocation( DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) { var actualSpan = actual.GetLineSpan(); Assert.IsTrue( actualSpan.Path == expected.Path || actualSpan.Path != null && actualSpan.Path.Contains("Test0.") && expected.Path.Contains("Test."), string.Format( "Expected diagnostic to be in file \"{0}\" was actually in file \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Path, actualSpan.Path, FormatDiagnostics(analyzer, diagnostic))); var actualLinePosition = actualSpan.StartLinePosition; // Only check line position if there is an actual line in the real diagnostic if (actualLinePosition.Line > 0) { if (actualLinePosition.Line + 1 != expected.Line) { Assert.IsTrue( false, string.Format( "Expected diagnostic to be on line \"{0}\" was actually on line \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Line, actualLinePosition.Line + 1, FormatDiagnostics(analyzer, diagnostic))); } } // Only check column position if there is an actual column position in the real diagnostic if (actualLinePosition.Character > 0) { if (actualLinePosition.Character + 1 != expected.Column) { Assert.IsTrue( false, string.Format( "Expected diagnostic to start at column \"{0}\" was actually at column \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Column, actualLinePosition.Character + 1, FormatDiagnostics(analyzer, diagnostic))); } } }
public void Initialize_DestructorDeclarationWithoutDocumentationHeader_DiagnosticDetected() { // Arrange string expectedMessage = "Element 'TestClass' should be documented."; var expectedLocation = new DiagnosticResultLocation("Test0.cs", 5, 4); DiagnosticResult expectedResult = this.CreateDiagnosticResult(expectedMessage, expectedLocation); string sourceCode = @" /// <summary>The summary.</summary> public class TestClass { ~TestClass() { } }"; // Act + Assert this.VerifyCSharpDiagnostic(sourceCode, expectedResult); }
/// <summary> /// Helper method to <see cref="VerifyDiagnosticResults"/> that checks the location of /// a diagnostic and compares it with the location in the expected /// <see cref="DiagnosticResult"/>. /// </summary> /// <param name="analyzer">The analyzer that was being run on the sources.</param> /// <param name="diagnostic">The diagnostic that was found in the code.</param> /// <param name="actual">The location of the diagnostic found in the code.</param> /// <param name="expected">The <see cref="DiagnosticResultLocation"/> that should have been /// found.</param> private static void VerifyDiagnosticLocation( DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected ) { var actualSpan = actual.GetLineSpan(); string msg = $"Expected diagnostic to be in file \"{expected.Path}\" was actually in file" + $" \"{actualSpan.Path}\"\r\n\r\nDiagnostic:" + $"\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"; Assert.True( actualSpan.Path == expected.Path || ( actualSpan.Path != null && actualSpan.Path.Contains($"{DefaultFilePathPrefix}0.") && expected.Path.Contains($"{DefaultFilePathPrefix}.") ), msg ); var actualLinePosition = actualSpan.StartLinePosition; // Only check line position if there is an actual line in the real diagnostic. if (actualLinePosition.Line > 0) { msg = $"Expected diagnostic to be on line \"{expected.Line}\" was actually on line" + $" \"{actualLinePosition.Line + 1}\"\r\n\r\nDiagnostic:" + $"\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"; Assert.True(actualLinePosition.Line + 1 == expected.Line, msg); } // Only check column position if there is an actual column position // in the real diagnostic. if (actualLinePosition.Character > 0) { msg = $"Expected diagnostic to start at column \"{expected.Column}\" was actually " + $"at column \"{actualLinePosition.Character + 1}\"\r\n\r\nDiagnostic:" + $"\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"; Assert.True(expected.Column == actualLinePosition.Character + 1, msg); } }
/// <summary> /// Helper method to VerifyDiagnosticResult that checks the location of a /// diagnostic and compares it with the location in the expected DiagnosticResult. /// </summary> /// <param name="analyzer"> The analyzer that was being run on the sources </param> /// <param name="diagnostic"> The diagnostic that was found in the code </param> /// <param name="actual"> The Location of the Diagnostic found in the code </param> /// <param name="expected"> /// The DiagnosticResultLocation that should have been /// found /// </param> private static VerifyDiagnosticAnalyzerResult VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) { var actualSpan = actual.GetLineSpan(); var isInExpectedFile = actualSpan.Path == expected.Path || actualSpan.Path != null && actualSpan.Path.Contains("Test0.") && expected.Path.Contains("Test."); if (!isInExpectedFile) { var msg = GetNotInExpectedFileMessage(analyzer, diagnostic, expected, actualSpan); return(VerifyDiagnosticAnalyzerResult.Fail(msg)); } var actualLinePosition = actualSpan.StartLinePosition; // Only check line position if there is an actual line in the real diagnostic if (actualLinePosition.Line > 0) { if (actualLinePosition.Line + 1 != expected.Line) { var msg = GetNotInExpectedLineMessage(analyzer, diagnostic, expected, actualLinePosition); return(VerifyDiagnosticAnalyzerResult.Fail(msg)); } } // Only check column position if there is an actual column position in the real diagnostic if (actualLinePosition.Character > 0) { if (actualLinePosition.Character + 1 != expected.Column) { var msg = GetNotInExpectedColumn(analyzer, diagnostic, expected, actualLinePosition); return(VerifyDiagnosticAnalyzerResult.Fail(msg)); } } return(VerifyDiagnosticAnalyzerResult.Ok()); }
private static DiagnosticResult GetResultAt(string path, int line, int column, DiagnosticDescriptor rule, params object[] messageArguments) { var location = new DiagnosticResultLocation(path, line, column); return new DiagnosticResult { Locations = new[] { location }, Id = rule.Id, Severity = rule.DefaultSeverity, Message = string.Format(rule.MessageFormat.ToString(), messageArguments) }; }
/// <summary> /// Helper method to VerifyDiagnosticResult that checks the location of a diagnostic and compares it with the location /// in the expected DiagnosticResult. /// </summary> /// <param name="analyzer">The analyzer that was being run on the sources</param> /// <param name="diagnostic">The diagnostic that was found in the code</param> /// <param name="actual">The Location of the Diagnostic found in the code</param> /// <param name="expected">The DiagnosticResultLocation that should have been found</param> private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) { if (expected.Line == null || expected.Column == null) { if (actual != Location.None) { Assert.Fail($"Expected:\nA project diagnostic with No location\nActual:\n{FormatDiagnostics(analyzer, diagnostic)}"); } } var actualSpan = actual.GetLineSpan(); Assert.AreEqual(actualSpan.Path, expected.FilePath, $"Expected diagnostic to be in file \"{expected.FilePath}\" was actually in file \"{actualSpan.Path}\"\r\n\r\nDiagnostic:\r\n{FormatDiagnostics(analyzer, diagnostic)}\r\n"); var actualLinePosition = actualSpan.StartLinePosition; if (actualLinePosition.Line + 1 != expected.Line) { Assert.Fail( $"Expected diagnostic to be on line \"{expected.Line}\" was actually on line \"{actualLinePosition.Line + 1}\"\r\n\r\nDiagnostic:\r\n{FormatDiagnostics(analyzer, diagnostic)}\r\n"); } if (actualLinePosition.Character + 1 != expected.Column) { Assert.Fail( $"Expected diagnostic to start at column \"{expected.Column}\" was actually at column \"{actualLinePosition.Character + 1}\"\r\n\r\nDiagnostic:\r\n{FormatDiagnostics(analyzer, diagnostic)}\r\n"); } }
/// <summary> /// Helper method to VerifyDiagnosticResult that checks the location of a diagnostic and compares it with the location in the expected DiagnosticResult. /// </summary> /// <param name="analyzer">The analyzer that was being run on the sources</param> /// <param name="diagnostic">The diagnostic that was found in the code</param> /// <param name="actual">The Location of the Diagnostic found in the code</param> /// <param name="expected">The DiagnosticResultLocation that should have been found</param> private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) { var actualSpan = actual.GetLineSpan(); Assert.True( actualSpan.Path == expected.Path || (actualSpan.Path != null && actualSpan.Path.Contains("Test0.") && expected.Path.Contains("Test.")), $"Expected diagnostic to be in file \"{expected.Path}\" was actually in file \"{actualSpan.Path}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); var actualLinePosition = actualSpan.StartLinePosition; // Only check line position if there is an actual line in the real diagnostic if (actualLinePosition.Line > 0) { if (actualLinePosition.Line + 1 != expected.Line) { Assert.True( false, $"Expected diagnostic to be on line \"{expected.Line}\" was actually on line \"{actualLinePosition.Line + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); } } // Only check column position if there is an actual column position in the real diagnostic if (actualLinePosition.Character > 0) { if (actualLinePosition.Character + 1 != expected.Column) { Assert.True( false, $"Expected diagnostic to start at column \"{expected.Column}\" was actually at column \"{actualLinePosition.Character + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); } } }
private static DiagnosticResult GetResultAt(string path, int line, int column, string id, string message) { var location = new DiagnosticResultLocation(path, line, column); return new DiagnosticResult { Locations = new[] { location }, Id = id, Severity = DiagnosticSeverity.Warning, Message = message }; }
/// <summary> /// Helper method to VerifyDiagnosticResult that checks the location of a diagnostic and compares it with the location in the expected DiagnosticResult. /// </summary> /// <param name="analyzer">The analyzer that was being run on the sources</param> /// <param name="diagnostic">The diagnostic that was found in the code</param> /// <param name="actual">The Location of the Diagnostic found in the code</param> /// <param name="expected">The DiagnosticResultLocation that should have been found</param> private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) { FileLinePositionSpan actualSpan = actual.GetLineSpan(); Assert.True(actualSpan.Path == expected.Path || (actualSpan.Path != null && actualSpan.Path.Contains("Test0.") && expected.Path.Contains("Test.")), string.Format("Expected diagnostic to be in file \"{0}\" was actually in file \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Path, actualSpan.Path, FormatDiagnostics(analyzer, diagnostic))); Microsoft.CodeAnalysis.Text.LinePosition actualLinePosition = actualSpan.StartLinePosition; // Only check line position if there is an actual line in the real diagnostic if (actualLinePosition.Line > 0) { if (actualLinePosition.Line + 1 != expected.Line) { Assert.True(false, string.Format("Expected diagnostic to be on line \"{0}\" was actually on line \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Line, actualLinePosition.Line + 1, FormatDiagnostics(analyzer, diagnostic))); } } // Only check column position if there is an actual column position in the real diagnostic if (actualLinePosition.Character > 0) { if (actualLinePosition.Character + 1 != expected.Column) { Assert.True(false, string.Format("Expected diagnostic to start at column \"{0}\" was actually at column \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Column, actualLinePosition.Character + 1, FormatDiagnostics(analyzer, diagnostic))); } } }
/// <summary> /// Helper method to VerifyDiagnosticResult that checks the location of a diagnostic and compares it with the location in /// the expected DiagnosticResult. /// </summary> /// <param name="analyzer">The analyzer that was being run on the sources.</param> /// <param name="diagnostic">The diagnostic that was found in the code.</param> /// <param name="actual">The Location of the Diagnostic found in the code.</param> /// <param name="expected">The DiagnosticResultLocation that should have been found.</param> static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) { var actualSpan = actual.GetLineSpan(); Assert.That( (actualSpan.Path == expected.Path) || ((actualSpan.Path != null) && actualSpan.Path.Contains("Test0.", StringComparison.OrdinalIgnoreCase) && expected.Path.Contains("Test.", StringComparison.OrdinalIgnoreCase)), Is.True, $"Expected diagnostic to be in file \"{expected.Path}\" was actually in file \"{actualSpan.Path}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); var actualLinePosition = actualSpan.StartLinePosition; // Only check line position if there is an actual line in the real diagnostic if (actualLinePosition.Line > 0) { if ((actualLinePosition.Line + 1) != expected.Line) { Assert.Fail( $"Expected diagnostic to be on line \"{expected.Line}\" was actually on line \"{actualLinePosition.Line + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); } } // Only check column position if there is an actual column position in the real diagnostic if (actualLinePosition.Character > 0) { if ((actualLinePosition.Character + 1) != expected.Column) { Assert.Fail( $"Expected diagnostic to start at column \"{expected.Column}\" was actually at column \"{actualLinePosition.Character + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); } } }
/// <summary> /// Helper method to VerifyDiagnosticResult that checks the location of a diagnostic and compares it with the location in the expected DiagnosticResult. /// </summary> /// <param name="analyzer">The analyzer that was being run on the sources</param> /// <param name="diagnostic">The diagnostic that was found in the code</param> /// <param name="actual">The Location of the Diagnostic found in the code</param> /// <param name="expected">The DiagnosticResultLocation that should have been found</param> private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) { var actualSpan = actual.GetLineSpan(); Assert.True(actualSpan.Path == expected.Path || (actualSpan.Path != null && actualSpan.Path.Contains("Test0.") && expected.Path.Contains("Test.")), $"Expected diagnostic to be in file \"{expected.Path}\" was actually in file \"{actualSpan.Path}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); var actualLinePosition = actualSpan.StartLinePosition; var actualLength = actual.SourceSpan.Length; // Only check line position if there is an actual line in the real diagnostic if (actualLinePosition.Line > 0) { if (actualLinePosition.Line + 1 != expected.Line) { Assert.True(false, $"Expected diagnostic to be on line \"{expected.Line}\" was actually on line \"{actualLinePosition.Line + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); } } // Only check column position if there is an actual column position in the real diagnostic if (actualLinePosition.Character > 0) { if (actualLinePosition.Character + 1 != expected.Column) { Assert.True(false, $"Expected diagnostic to start at column \"{expected.Column}\" was actually at column \"{actualLinePosition.Character + 1}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); } } // Check length if there is an expected length if (expected.Length > 0) { if (actualLength != expected.Length) { Assert.True(false, $"Expected diagnostic to have length \"{expected.Length}\" was actually length \"{actualLength}\"\r\n\r\nDiagnostic:\r\n {FormatDiagnostics(analyzer, diagnostic)}\r\n"); } } }
private static IEnumerable <GeneratorTheoryData> GetTestCases() { var enumerationTypeFullName = typeof(Enumeration).FullName; var flagsEnumerationTypeFullName = typeof(FlagsEnumerationAttribute).FullName; var fileName = $"{DefaultFilePathPrefix}.{CSharpDefaultFileExt}"; yield return(new GeneratorTheoryData { Description = "Empty source", GivenSource = Empty }); { const string g = "public class TestClass {}"; yield return(new GeneratorTheoryData { Description = $"ignore non-{enumerationTypeFullName} classes", GivenSource = g, FixedSource = g }); } { /* Whereas the inspiration behind this approach, Record Generator, was * doing something like "crop raw indent", I think we just leverage the * built in language features and enter it as such. If we cannot deal with * that, so be it. * https://github.com/amis92/RecordGenerator/blob/f761bcf58a894bcc15233dbb465747a21c6da53c/test/Amadevus.RecordGenerator.Analyzers.Test/Helpers/Extensions.cs#L14 */ const string g = @"using Ellumination.Collections; namespace MyClasses { public class TestClass : Enumeration<TestClass> { } }"; yield return(new GeneratorTheoryData { Description = $"ignore undecorated {enumerationTypeFullName} class", GivenSource = g, FixedSource = g }); } { const string g = @"using Ellumination.Collections; namespace MyClasses { [FlagsEnumeration] public partial class TestClass : Enumeration<TestClass> { } }"; yield return(new GeneratorTheoryData { Description = $"nothing to do for partial [{flagsEnumerationTypeFullName}] {enumerationTypeFullName} class", GivenSource = g, FixedSource = g }); } { /* The extrinsic comments and spacing here are VERY intentional and serve * to illustrate where we expect the diagnostic to occur in relation to the * provided source code. */ const int line = 5; const int character = 17; const string g = @"using Ellumination.Collections; namespace MyClasses { [FlagsEnumeration] public class TestClass : Enumeration<TestClass>" /* * ^ we expect error requiring correction precisely here, * literally line 6 (5+1) character 18 (17+1) */ + @" { } }"; const string f = @"using Ellumination.Collections; namespace MyClasses { [FlagsEnumeration] public partial class TestClass : Enumeration<TestClass> { } }"; yield return(new GeneratorTheoryData { Description = $"transform non-partial [{flagsEnumerationTypeFullName}] {enumerationTypeFullName} class", GivenSource = g, FixedSource = f, ExpectedDiagnostics = DiagnosticResult.Create(X1000_DerivedEnumerationMustBePartial , DiagnosticResultLocation.Create(fileName, line + 1, character + 1)).ToArrayArray() }); } }