From 95b9173de499c64197cbba19779d359e8b30b1a5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2020 04:13:09 +0000 Subject: [PATCH 01/31] Bump Microsoft.NET.Test.Sdk from 16.4.0 to 16.6.0 in /src Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.4.0 to 16.6.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.4.0...v16.6.0) Signed-off-by: dependabot-preview[bot] --- src/Cake.Issues.Tests/Cake.Issues.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj b/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj index 23d9e2e35..0694ceea8 100644 --- a/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj +++ b/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj @@ -25,7 +25,7 @@ - + From d0f14c255fb0eefc0bae69e8edab7f9d240cc7da Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2020 10:04:58 +0000 Subject: [PATCH 02/31] Bump Microsoft.NET.Test.Sdk from 16.6.0 to 16.6.1 in /src Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.6.0 to 16.6.1. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.6.0...v16.6.1) Signed-off-by: dependabot-preview[bot] --- src/Cake.Issues.Tests/Cake.Issues.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj b/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj index 0694ceea8..1768f6e97 100644 --- a/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj +++ b/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj @@ -25,7 +25,7 @@ - + From 538206f8973c0924c549a03ffb6c4ee421db5fb0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2020 23:43:13 +0000 Subject: [PATCH 03/31] Bump Microsoft.CodeAnalysis.FxCopAnalyzers from 2.9.8 to 3.0.0 in /src Bumps [Microsoft.CodeAnalysis.FxCopAnalyzers](https://github.com/dotnet/roslyn-analyzers) from 2.9.8 to 3.0.0. - [Release notes](https://github.com/dotnet/roslyn-analyzers/releases) - [Changelog](https://github.com/dotnet/roslyn-analyzers/blob/master/PostReleaseActivities.md) - [Commits](https://github.com/dotnet/roslyn-analyzers/compare/v2.9.8...v3.0.0) Signed-off-by: dependabot-preview[bot] --- src/Cake.Issues.Testing/Cake.Issues.Testing.csproj | 2 +- src/Cake.Issues/Cake.Issues.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cake.Issues.Testing/Cake.Issues.Testing.csproj b/src/Cake.Issues.Testing/Cake.Issues.Testing.csproj index 4347c3be9..ef03c32ac 100644 --- a/src/Cake.Issues.Testing/Cake.Issues.Testing.csproj +++ b/src/Cake.Issues.Testing/Cake.Issues.Testing.csproj @@ -26,7 +26,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Cake.Issues/Cake.Issues.csproj b/src/Cake.Issues/Cake.Issues.csproj index bafe543eb..0bbfc481a 100644 --- a/src/Cake.Issues/Cake.Issues.csproj +++ b/src/Cake.Issues/Cake.Issues.csproj @@ -24,7 +24,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From ae6b256ca03ff78cbd532805820ccfc991677a0a Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Mon, 27 Apr 2020 22:14:17 +0200 Subject: [PATCH 04/31] Remove duplicated tests --- src/Cake.Issues.Tests/IssueBuilderTests.cs | 39 ---------------------- 1 file changed, 39 deletions(-) diff --git a/src/Cake.Issues.Tests/IssueBuilderTests.cs b/src/Cake.Issues.Tests/IssueBuilderTests.cs index d73fb1bf5..0f67a1d0b 100644 --- a/src/Cake.Issues.Tests/IssueBuilderTests.cs +++ b/src/Cake.Issues.Tests/IssueBuilderTests.cs @@ -526,45 +526,6 @@ public void Should_Set_FilePath(string filePath, string expectedFilePath) public sealed class TheInFileLineMethod { - [Fact] - public void Should_Handle_File_Paths_Which_Are_Null() - { - // Given - var fixture = new IssueBuilderFixture(); - - // When - var issue = fixture.IssueBuilder.InFile(null).Create(); - - // Then - issue.AffectedFileRelativePath.ShouldBe(null); - } - - [Fact] - public void Should_Handle_File_Paths_Which_Are_Empty() - { - // Given - var fixture = new IssueBuilderFixture(); - - // When - var issue = fixture.IssueBuilder.InFile(string.Empty).Create(); - - // Then - issue.AffectedFileRelativePath.ShouldBe(null); - } - - [Fact] - public void Should_Handle_File_Paths_Which_Are_WhiteSpace() - { - // Given - var fixture = new IssueBuilderFixture(); - - // When - var issue = fixture.IssueBuilder.InFile(" ").Create(); - - // Then - issue.AffectedFileRelativePath.ShouldBe(null); - } - [Fact] public void Should_Throw_If_Line_Is_Negative() { From 09fc689d551c40057d15c5d5aa2426eda51b1ab9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2020 10:42:26 +0000 Subject: [PATCH 05/31] Bump xunit.runner.visualstudio from 2.4.1 to 2.4.2 in /src Bumps [xunit.runner.visualstudio](https://github.com/xunit/visualstudio.xunit) from 2.4.1 to 2.4.2. - [Release notes](https://github.com/xunit/visualstudio.xunit/releases) - [Commits](https://github.com/xunit/visualstudio.xunit/commits/v2.4.2) Signed-off-by: dependabot-preview[bot] --- src/Cake.Issues.Tests/Cake.Issues.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj b/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj index 1768f6e97..1fe81c376 100644 --- a/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj +++ b/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj @@ -34,7 +34,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + From e9e81281e93c8aa485dcff041a4a517f50525552 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Mon, 27 Apr 2020 22:12:03 +0200 Subject: [PATCH 06/31] (GH-165) Add column to IIssue --- src/Cake.Issues.Testing/IssueChecker.cs | 10 + .../Cake.Issues.Tests.csproj | 6 + src/Cake.Issues.Tests/IIssueComparerTests.cs | 92 ++++++ .../IIssueExtensionsTests.cs | 3 +- src/Cake.Issues.Tests/IssueBuilderTests.cs | 124 ++++++++ src/Cake.Issues.Tests/IssueTests.cs | 297 +++++++++++++++++- .../IssueDeserializationExtensionsTests.cs | 60 ++++ .../IssueSerializationExtensionsTests.cs | 116 +++++++ .../SerializableIssueV3ExtensionsTests.cs | 25 ++ src/Cake.Issues.Tests/Testfiles/issueV3.json | 17 + src/Cake.Issues.Tests/Testfiles/issuesV3.json | 36 +++ .../Testing/IssueCheckerFixture.cs | 5 +- .../Testing/IssueCheckerTests.cs | 54 +++- src/Cake.Issues/IIssue.cs | 6 + src/Cake.Issues/IIssueComparer.cs | 5 + src/Cake.Issues/IIssueExtensions.cs | 5 + src/Cake.Issues/Issue.cs | 13 + src/Cake.Issues/IssueBuilder.cs | 25 ++ .../IssueDeserializationExtensions.cs | 2 + .../IssueSerializationExtensions.cs | 7 +- .../SerializableIssueExtensions.cs | 1 + .../SerializableIssueV2Extensions.cs | 1 + .../Serialization/SerializableIssueV3.cs | 79 +++++ .../SerializableIssueV3Extensions.cs | 48 +++ 24 files changed, 1029 insertions(+), 8 deletions(-) create mode 100644 src/Cake.Issues.Tests/Serialization/SerializableIssueV3ExtensionsTests.cs create mode 100644 src/Cake.Issues.Tests/Testfiles/issueV3.json create mode 100644 src/Cake.Issues.Tests/Testfiles/issuesV3.json create mode 100644 src/Cake.Issues/Serialization/SerializableIssueV3.cs create mode 100644 src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs diff --git a/src/Cake.Issues.Testing/IssueChecker.cs b/src/Cake.Issues.Testing/IssueChecker.cs index d68a51799..6a83423f9 100644 --- a/src/Cake.Issues.Testing/IssueChecker.cs +++ b/src/Cake.Issues.Testing/IssueChecker.cs @@ -45,6 +45,7 @@ public static void Check( expectedIssue.ProjectName, expectedIssue.AffectedFileRelativePath?.ToString(), expectedIssue.Line, + expectedIssue.Column, expectedIssue.MessageText, expectedIssue.MessageHtml, expectedIssue.MessageMarkdown, @@ -68,6 +69,8 @@ public static void Check( /// null if the issue is not expected to be related to a change in a file. /// Expected line number. /// null if the issue is not expected to be related to a file or specific line. + /// Expected column. + /// null if the issue is not expected to be related to a file or specific column. /// Expected message in plain text format. /// Expected message in HTML format. /// Expected message in Markdown format. @@ -87,6 +90,7 @@ public static void Check( string projectName, string affectedFileRelativePath, int? line, + int? column, string messageText, string messageHtml, string messageMarkdown, @@ -167,6 +171,12 @@ public static void Check( $"Expected issue.Line to be '{line}' but was '{issue.Line}'."); } + if (issue.Column != column) + { + throw new Exception( + $"Expected issue.Column to be '{column}' but was '{issue.Column}'."); + } + if (issue.MessageText != messageText) { throw new Exception( diff --git a/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj b/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj index 1fe81c376..a21b89da7 100644 --- a/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj +++ b/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj @@ -43,9 +43,15 @@ + + Always + Always + + Always + Always diff --git a/src/Cake.Issues.Tests/IIssueComparerTests.cs b/src/Cake.Issues.Tests/IIssueComparerTests.cs index 169003a5a..b7a412f0a 100644 --- a/src/Cake.Issues.Tests/IIssueComparerTests.cs +++ b/src/Cake.Issues.Tests/IIssueComparerTests.cs @@ -131,6 +131,30 @@ public void Should_Return_False_If_Line_Is_Different(int? line1, int? line2) CompareIssues(issue1, issue2, false); } + [Theory] + [InlineData(1, 2)] + [InlineData(1, null)] + [InlineData(null, 1)] + [InlineData(int.MaxValue, 1)] + [InlineData(1, int.MaxValue)] + public void Should_Return_False_If_Column_Is_Different(int? column1, int? column2) + { + // Given + var issue1 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile("foo", 42, column1) + .Create(); + var issue2 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile("foo", 42, column2) + .Create(); + + // When / Then + CompareIssues(issue1, issue2, false); + } + [Fact] public void Should_Return_False_If_MessageText_Is_Different() { @@ -467,6 +491,28 @@ public void Should_Return_True_If_Line_Is_Same(int? line1, int? line2) CompareIssues(issue1, issue2, true); } + [Theory] + [InlineData(1, 1)] + [InlineData(null, null)] + [InlineData(int.MaxValue, int.MaxValue)] + public void Should_Return_True_If_Column_Is_Same(int? column1, int? column2) + { + // Given + var issue1 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile("foo", 42, column1) + .Create(); + var issue2 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile("foo", 42, column2) + .Create(); + + // When / Then + CompareIssues(issue1, issue2, true); + } + [Fact] public void Should_Return_True_If_MessageText_Is_Same() { @@ -1173,6 +1219,52 @@ public void Should_Return_True_If_Line_Is_Same(int? line1, int? line2) CompareIssues(issue1, issue2, true); } + [Theory] + [InlineData(1, 2)] + [InlineData(1, null)] + [InlineData(null, 1)] + [InlineData(int.MaxValue, 1)] + [InlineData(1, int.MaxValue)] + public void Should_Return_True_If_Column_Is_Different(int? column1, int? column2) + { + // Given + var issue1 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile("foo", 42, column1) + .Create(); + var issue2 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile("foo", 42, column2) + .Create(); + + // When / Then + CompareIssues(issue1, issue2, true); + } + + [Theory] + [InlineData(1, 1)] + [InlineData(null, null)] + [InlineData(int.MaxValue, int.MaxValue)] + public void Should_Return_True_If_Column_Is_Same(int? column1, int? column2) + { + // Given + var issue1 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile("foo", 42, column1) + .Create(); + var issue2 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile("foo", 42, column2) + .Create(); + + // When / Then + CompareIssues(issue1, issue2, true); + } + [Fact] public void Should_Return_True_If_MessageText_Is_Same() { diff --git a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs index c444ac375..58db8d4a0 100644 --- a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs +++ b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs @@ -306,6 +306,7 @@ public void Should_Throw_If_Issue_Is_Null() [InlineData("foo {FileDirectory} bar", "foo src/Cake.Issues bar")] [InlineData("foo {FileName} bar", "foo foo.cs bar")] [InlineData("foo {Line} bar", "foo 42 bar")] + [InlineData("foo {Column} bar", "foo 23 bar")] [InlineData("foo {Rule} bar", "foo Rule Foo bar")] [InlineData("foo {RuleUrl} bar", "foo https://google.com/ bar")] [InlineData("foo {MessageText} bar", "foo MessageText Foo bar")] @@ -319,7 +320,7 @@ public void Should_Replace_Tokens(string pattern, string expectedResult) .NewIssue("MessageText Foo", "ProviderType Foo", "ProviderName Foo") .WithMessageInHtmlFormat("MessageHtml Foo") .WithMessageInMarkdownFormat("MessageMarkdown Foo") - .InFile(@"src/Cake.Issues/foo.cs", 42) + .InFile(@"src/Cake.Issues/foo.cs", 42, 23) .InProject(@"src/Cake.Issues/Cake.Issues.csproj", "Cake.Issues") .OfRule("Rule Foo", new Uri("https://google.com")) .WithPriority(IssuePriority.Error) diff --git a/src/Cake.Issues.Tests/IssueBuilderTests.cs b/src/Cake.Issues.Tests/IssueBuilderTests.cs index 0f67a1d0b..9e8ac88ef 100644 --- a/src/Cake.Issues.Tests/IssueBuilderTests.cs +++ b/src/Cake.Issues.Tests/IssueBuilderTests.cs @@ -606,6 +606,130 @@ public void Should_Set_Line(int line) } } + public sealed class TheInFileLineColumnMethod + { + public void Should_Throw_If_Line_Is_Negative() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", -1, 50)); + + // Then + result.IsArgumentOutOfRangeException("line"); + } + + [Fact] + public void Should_Throw_If_Line_Is_Zero() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", 0, 50)); + + // Then + result.IsArgumentOutOfRangeException("line"); + } + + [Fact] + public void Should_Throw_If_Column_Is_Negative() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", 100, -1)); + + // Then + result.IsArgumentOutOfRangeException("column"); + } + + [Fact] + public void Should_Throw_If_Column_Is_Zero() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", 100, 0)); + + // Then + result.IsArgumentOutOfRangeException("column"); + } + + [Fact] + public void Should_Handle_Column_Which_Is_Null() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", 100, null).Create(); + + // Then + issue.Column.ShouldBe(null); + } + + [Theory] + [InlineData(@"foo", @"foo")] + [InlineData(@"foo\bar", @"foo/bar")] + [InlineData(@"foo/bar", @"foo/bar")] + [InlineData(@"foo\bar\", @"foo/bar")] + [InlineData(@"foo/bar/", @"foo/bar")] + [InlineData(@".\foo", @"foo")] + [InlineData(@"./foo", @"foo")] + [InlineData(@"foo\..\bar", @"foo/../bar")] + [InlineData(@"foo/../bar", @"foo/../bar")] + public void Should_Set_FilePath(string filePath, string expectedFilePath) + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile(filePath, 10, 50).Create(); + + // Then + issue.AffectedFileRelativePath.ToString().ShouldBe(expectedFilePath); + issue.AffectedFileRelativePath.IsRelative.ShouldBe(true, "File path was not set as relative."); + } + + [Theory] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void Should_Set_Line(int line) + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", line, 50).Create(); + + // Then + issue.Line.ShouldBe(line); + } + + [Theory] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void Should_Set_Column(int column) + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", 100, column).Create(); + + // Then + issue.Column.ShouldBe(column); + } + } + public sealed class TheWithPriorityMethod { [Fact] diff --git a/src/Cake.Issues.Tests/IssueTests.cs b/src/Cake.Issues.Tests/IssueTests.cs index 5a5d9b7ea..84ddce339 100644 --- a/src/Cake.Issues.Tests/IssueTests.cs +++ b/src/Cake.Issues.Tests/IssueTests.cs @@ -19,6 +19,7 @@ public void Should_Throw_If_Project_Path_Is_Invalid(string projectPath) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 100; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -36,6 +37,7 @@ public void Should_Throw_If_Project_Path_Is_Invalid(string projectPath) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -60,6 +62,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string projectPath) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 100; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -77,6 +80,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string projectPath) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -99,6 +103,7 @@ public void Should_Handle_Project_Paths_Which_Are_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -116,6 +121,7 @@ public void Should_Handle_Project_Paths_Which_Are_Null() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -138,6 +144,7 @@ public void Should_Handle_Project_Paths_Which_Are_Empty() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -155,6 +162,7 @@ public void Should_Handle_Project_Paths_Which_Are_Empty() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -177,6 +185,7 @@ public void Should_Handle_Project_Paths_Which_Are_WhiteSpace() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -194,6 +203,7 @@ public void Should_Handle_Project_Paths_Which_Are_WhiteSpace() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -216,6 +226,7 @@ public void Should_Set_ProjectFileRelativePath(string projectPath) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -233,6 +244,7 @@ public void Should_Set_ProjectFileRelativePath(string projectPath) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -258,6 +270,7 @@ public void Should_Handle_Projects_Which_Are_Null() string projectName = null; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -275,6 +288,7 @@ public void Should_Handle_Projects_Which_Are_Null() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -297,6 +311,7 @@ public void Should_Handle_Projects_Which_Are_Empty() var projectName = string.Empty; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -314,6 +329,7 @@ public void Should_Handle_Projects_Which_Are_Empty() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -336,6 +352,7 @@ public void Should_Handle_Projects_Which_Are_WhiteSpace() var projectName = " "; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -353,6 +370,7 @@ public void Should_Handle_Projects_Which_Are_WhiteSpace() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -375,6 +393,7 @@ public void Should_Set_ProjectName(string projectName) var projectPath = @"src\foo.csproj"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -392,6 +411,7 @@ public void Should_Set_ProjectName(string projectName) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -417,6 +437,7 @@ public void Should_Throw_If_File_Path_Is_Invalid(string filePath) var projectPath = @"src\foo.csproj"; var projectName = "foo"; var line = 100; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -434,6 +455,7 @@ public void Should_Throw_If_File_Path_Is_Invalid(string filePath) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -458,6 +480,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string filePath) var projectPath = @"src\foo.csproj"; var projectName = "foo"; var line = 100; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -475,6 +498,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string filePath) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -497,6 +521,7 @@ public void Should_Handle_File_Paths_Which_Are_Null() var projectName = "foo"; string filePath = null; int? line = null; + int? column = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -514,6 +539,7 @@ public void Should_Handle_File_Paths_Which_Are_Null() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -536,6 +562,7 @@ public void Should_Handle_File_Paths_Which_Are_Empty() var projectName = "foo"; var filePath = string.Empty; int? line = null; + int? column = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -553,6 +580,7 @@ public void Should_Handle_File_Paths_Which_Are_Empty() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -575,6 +603,7 @@ public void Should_Handle_File_Paths_Which_Are_WhiteSpace() var projectName = "foo"; var filePath = " "; int? line = null; + int? column = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -592,6 +621,7 @@ public void Should_Handle_File_Paths_Which_Are_WhiteSpace() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -622,6 +652,7 @@ public void Should_Set_File_Path(string filePath, string expectedFilePath) var projectPath = @"src\foo.csproj"; var projectName = "foo"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -639,6 +670,7 @@ public void Should_Set_File_Path(string filePath, string expectedFilePath) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -665,6 +697,7 @@ public void Should_Throw_If_Line_Is_Negative() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = -1; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -682,6 +715,7 @@ public void Should_Throw_If_Line_Is_Negative() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -704,6 +738,7 @@ public void Should_Throw_If_Line_Is_Zero() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 0; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -721,6 +756,7 @@ public void Should_Throw_If_Line_Is_Zero() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -743,6 +779,7 @@ public void Should_Throw_If_Line_Is_Set_But_No_File() var projectName = "foo"; string filePath = null; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -760,6 +797,7 @@ public void Should_Throw_If_Line_Is_Set_But_No_File() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -774,16 +812,57 @@ public void Should_Throw_If_Line_Is_Set_But_No_File() result.IsArgumentOutOfRangeException("line"); } + [Fact] + public void Should_Handle_Line_Which_Is_Null() + { + // Given + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + int? line = null; + int? column = null; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var issue = + new Issue( + projectPath, + projectName, + filePath, + line, + column, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + providerType, + providerName); + + // Then + issue.Line.ShouldBe(line); + } + [Theory] - [InlineData(null)] [InlineData(1)] [InlineData(int.MaxValue)] - public void Should_Set_Line(int? line) + public void Should_Set_Line(int line) { // Given var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -801,6 +880,7 @@ public void Should_Set_Line(int? line) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -816,6 +896,175 @@ public void Should_Set_Line(int? line) } } + public sealed class TheColumnArgument + { + [Fact] + public void Should_Throw_If_Column_Is_Negative() + { + // Given + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 100; + var column = -1; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + new Issue( + projectPath, + projectName, + filePath, + line, + column, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("column"); + } + + [Fact] + public void Should_Throw_If_Column_Is_Zero() + { + // Given + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 100; + var column = 0; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + new Issue( + projectPath, + projectName, + filePath, + line, + column, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("column"); + } + + [Fact] + public void Should_Throw_If_Column_Is_Set_But_No_Line() + { + // Given + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + int? line = null; + var column = 50; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + new Issue( + projectPath, + projectName, + filePath, + line, + column, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("column"); + } + + [Theory] + [InlineData(null)] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void Should_Set_Column(int? column) + { + // Given + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 100; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var issue = + new Issue( + projectPath, + projectName, + filePath, + line, + column, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + providerType, + providerName); + + // Then + issue.Column.ShouldBe(column); + } + } + public sealed class TheMessageTextArgument { [Fact] @@ -826,6 +1075,7 @@ public void Should_Throw_If_MessageText_Is_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; string messageText = null; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -843,6 +1093,7 @@ public void Should_Throw_If_MessageText_Is_Null() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -865,6 +1116,7 @@ public void Should_Throw_If_MessageText_Is_Empty() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = string.Empty; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -882,6 +1134,7 @@ public void Should_Throw_If_MessageText_Is_Empty() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -904,6 +1157,7 @@ public void Should_Throw_If_MessageText_Is_WhiteSpace() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = " "; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -921,6 +1175,7 @@ public void Should_Throw_If_MessageText_Is_WhiteSpace() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -944,6 +1199,7 @@ public void Should_Set_MessageText(string messageText) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; var priority = 1; @@ -960,6 +1216,7 @@ public void Should_Set_MessageText(string messageText) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -989,6 +1246,7 @@ public void Should_Set_MessageHtml(string messageHtml) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageMarkdown = "MessageMarkdown"; var priority = 1; @@ -1005,6 +1263,7 @@ public void Should_Set_MessageHtml(string messageHtml) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1034,6 +1293,7 @@ public void Should_Set_MessageHtml(string messageMarkdown) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var priority = 1; @@ -1050,6 +1310,7 @@ public void Should_Set_MessageHtml(string messageMarkdown) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1081,6 +1342,7 @@ public void Should_Set_Priority(int? priority) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1097,6 +1359,7 @@ public void Should_Set_Priority(int? priority) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1122,6 +1385,7 @@ public void Should_Handle_PriorityNames_Which_Are_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1139,6 +1403,7 @@ public void Should_Handle_PriorityNames_Which_Are_Null() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1161,6 +1426,7 @@ public void Should_Handle_PriorityNames_Which_Are_Empty() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1178,6 +1444,7 @@ public void Should_Handle_PriorityNames_Which_Are_Empty() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1200,6 +1467,7 @@ public void Should_Handle_PriorityNames_Which_Are_WhiteSpace() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1217,6 +1485,7 @@ public void Should_Handle_PriorityNames_Which_Are_WhiteSpace() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1240,6 +1509,7 @@ public void Should_Set_Priority_Name(string priorityName) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1256,6 +1526,7 @@ public void Should_Set_Priority_Name(string priorityName) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1284,6 +1555,7 @@ public void Should_Set_Rule(string rule) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1300,6 +1572,7 @@ public void Should_Set_Rule(string rule) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1325,6 +1598,7 @@ public void Should_Set_Rule_Url() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1342,6 +1616,7 @@ public void Should_Set_Rule_Url() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1364,6 +1639,7 @@ public void Should_Set_Rule_Url_If_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1381,6 +1657,7 @@ public void Should_Set_Rule_Url_If_Null() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1406,6 +1683,7 @@ public void Should_Throw_If_Provider_Type_Is_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1423,6 +1701,7 @@ public void Should_Throw_If_Provider_Type_Is_Null() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1445,6 +1724,7 @@ public void Should_Throw_If_Provider_Type_Is_Empty() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1462,6 +1742,7 @@ public void Should_Throw_If_Provider_Type_Is_Empty() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1484,6 +1765,7 @@ public void Should_Throw_If_Provider_Type_Is_WhiteSpace() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1501,6 +1783,7 @@ public void Should_Throw_If_Provider_Type_Is_WhiteSpace() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1524,6 +1807,7 @@ public void Should_Set_ProviderType(string providerType) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1540,6 +1824,7 @@ public void Should_Set_ProviderType(string providerType) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1565,6 +1850,7 @@ public void Should_Throw_If_Provider_Name_Is_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1582,6 +1868,7 @@ public void Should_Throw_If_Provider_Name_Is_Null() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1604,6 +1891,7 @@ public void Should_Throw_If_Provider_Name_Is_Empty() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1621,6 +1909,7 @@ public void Should_Throw_If_Provider_Name_Is_Empty() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1643,6 +1932,7 @@ public void Should_Throw_If_Provider_Name_Is_WhiteSpace() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1660,6 +1950,7 @@ public void Should_Throw_If_Provider_Name_Is_WhiteSpace() projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, @@ -1683,6 +1974,7 @@ public void Should_Set_ProviderName(string providerName) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var column = 50; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1699,6 +1991,7 @@ public void Should_Set_ProviderName(string providerName) projectName, filePath, line, + column, messageText, messageHtml, messageMarkdown, diff --git a/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs b/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs index f2ad8facb..60646901a 100644 --- a/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs +++ b/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs @@ -128,6 +128,30 @@ public void Should_Return_IssueV2() .OfRule("Rule", new Uri("https://google.com")) .WithPriority(IssuePriority.Warning)); } + + [Fact] + public void Should_Return_IssueV3() + { + // Given + var filePath = new FilePath("Testfiles/issueV3.json"); + + // When + var result = filePath.DeserializeToIssue(); + + // Then + IssueChecker.Check( + result, + IssueBuilder.NewIssue( + "Something went wrong.", + "TestProvider", + "Test Provider") + .WithMessageInHtmlFormat("Something went wrong.") + .WithMessageInMarkdownFormat("Something went **wrong**.") + .InProject(@"src\Foo\Bar.csproj", "Bar") + .InFile(@"src\Foo\Bar.cs", 42, 23) + .OfRule("Rule", new Uri("https://google.com")) + .WithPriority(IssuePriority.Warning)); + } } public sealed class TheDeserializeToIssuesExtensionForAJsonFile @@ -225,6 +249,42 @@ public void Should_Return_List_Of_IssuesV2() .InFile(@"src\Foo\Bar2.cs") .WithPriority(IssuePriority.Warning)); } + + [Fact] + public void Should_Return_List_Of_IssuesV3() + { + // Given + var filePath = new FilePath("Testfiles/issuesV3.json"); + + // When + var result = filePath.DeserializeToIssues().ToList(); + + // Then + result.Count.ShouldBe(2); + IssueChecker.Check( + result[0], + IssueBuilder.NewIssue( + "Something went wrong.", + "TestProvider", + "Test Provider") + .WithMessageInHtmlFormat("Something went wrong.") + .WithMessageInMarkdownFormat("Something went **wrong**.") + .InProject(@"src\Foo\Bar.csproj", "Bar") + .InFile(@"src\Foo\Bar.cs", 42, 23) + .OfRule("Rule", new Uri("https://google.com")) + .WithPriority(IssuePriority.Warning)); + IssueChecker.Check( + result[1], + IssueBuilder.NewIssue( + "Something went wrong again.", + "TestProvider", + "Test Provider") + .WithMessageInHtmlFormat("Something went wrong again.") + .WithMessageInMarkdownFormat("Something went **wrong** again.") + .InProject(@"src\Foo\Bar.csproj", "Bar") + .InFile(@"src\Foo\Bar2.cs") + .WithPriority(IssuePriority.Warning)); + } } } } \ No newline at end of file diff --git a/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs b/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs index a280ff2af..34bb7f391 100644 --- a/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs +++ b/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs @@ -185,6 +185,24 @@ public void Should_Give_Correct_Result_For_Line_After_Roundtrip() result.Line.ShouldBe(line); } + [Fact] + public void Should_Give_Correct_Result_For_Column_After_Roundtrip() + { + // Given + var column = 23; + var issue = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile(@"src/foo.bar", 42, column) + .Create(); + + // When + var result = issue.SerializeToJsonString().DeserializeToIssue(); + + // Then + result.Column.ShouldBe(column); + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { @@ -519,6 +537,34 @@ public void Should_Give_Correct_Result_For_Line_After_Roundtrip() result.Last().Line.ShouldBe(line2); } + [Fact] + public void Should_Give_Correct_Result_For_Column_After_Roundtrip() + { + // Given + var column1 = 23; + var column2 = 42; + var issues = + new List + { + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .InFile(@"src/foo.bar", 123, column1) + .Create(), + IssueBuilder + .NewIssue("message2", "providerType2", "providerName2") + .InFile(@"src/foo.bar", 123, column2) + .Create(), + }; + + // When + var result = issues.SerializeToJsonString().DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().Column.ShouldBe(column1); + result.Last().Column.ShouldBe(column2); + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { @@ -932,6 +978,36 @@ public void Should_Give_Correct_Result_For_Line_After_Roundtrip() } } + [Fact] + public void Should_Give_Correct_Result_For_Column_After_Roundtrip() + { + // Given + var column = 23; + var issue = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile(@"src/foo.bar", 42, column) + .Create(); + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issue.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssue(); + + // Then + result.Column.ShouldBe(column); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { @@ -1437,6 +1513,46 @@ public void Should_Give_Correct_Result_For_Line_After_Roundtrip() } } + [Fact] + public void Should_Give_Correct_Result_For_Column_After_Roundtrip() + { + // Given + var column1 = 23; + var column2 = 42; + var issues = + new List + { + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .InFile(@"src/foo.bar", 123, column1) + .Create(), + IssueBuilder + .NewIssue("message2", "providerType2", "providerName2") + .InFile(@"src/foo.bar", 123, column2) + .Create(), + }; + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issues.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().Column.ShouldBe(column1); + result.Last().Column.ShouldBe(column2); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { diff --git a/src/Cake.Issues.Tests/Serialization/SerializableIssueV3ExtensionsTests.cs b/src/Cake.Issues.Tests/Serialization/SerializableIssueV3ExtensionsTests.cs new file mode 100644 index 000000000..c223b55cb --- /dev/null +++ b/src/Cake.Issues.Tests/Serialization/SerializableIssueV3ExtensionsTests.cs @@ -0,0 +1,25 @@ +namespace Cake.Issues.Tests.Serialization +{ + using Cake.Issues.Serialization; + using Cake.Issues.Testing; + using Xunit; + + public sealed class SerializableIssueV3ExtensionsTests + { + public sealed class TheToIssueExtension + { + [Fact] + public void Should_Throw_If_SerializableIssue_Is_Null() + { + // Given + SerializableIssueV3 serializableIssue = null; + + // When + var result = Record.Exception(() => serializableIssue.ToIssue()); + + // Then + result.IsArgumentNullException("serializableIssue"); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Tests/Testfiles/issueV3.json b/src/Cake.Issues.Tests/Testfiles/issueV3.json new file mode 100644 index 000000000..fa44b3df7 --- /dev/null +++ b/src/Cake.Issues.Tests/Testfiles/issueV3.json @@ -0,0 +1,17 @@ +{ + "Version": 3, + "AffectedFileRelativePath": "src\/Foo\/Bar.cs", + "Line": 42, + "Column": 23, + "MessageText": "Something went wrong.", + "MessageHtml": "Something went wrong.", + "MessageMarkdown": "Something went **wrong**.", + "Priority": 300, + "PriorityName": "Warning", + "ProjectFileRelativePath": "src\/Foo\/Bar.csproj", + "ProjectName": "Bar", + "ProviderName": "Test Provider", + "ProviderType": "TestProvider", + "Rule": "Rule", + "RuleUrl": "https://google.com" +} \ No newline at end of file diff --git a/src/Cake.Issues.Tests/Testfiles/issuesV3.json b/src/Cake.Issues.Tests/Testfiles/issuesV3.json new file mode 100644 index 000000000..89985df73 --- /dev/null +++ b/src/Cake.Issues.Tests/Testfiles/issuesV3.json @@ -0,0 +1,36 @@ +[ + { + "Version": 3, + "AffectedFileRelativePath": "src\/Foo\/Bar.cs", + "Line": 42, + "Column": 23, + "MessageText": "Something went wrong.", + "MessageHtml": "Something went wrong.", + "MessageMarkdown": "Something went **wrong**.", + "Priority": 300, + "PriorityName": "Warning", + "ProjectFileRelativePath": "src\/Foo\/Bar.csproj", + "ProjectName": "Bar", + "ProviderName": "Test Provider", + "ProviderType": "TestProvider", + "Rule": "Rule", + "RuleUrl": "https://google.com" + }, + { + "Version": 3, + "AffectedFileRelativePath": "src\/Foo\/Bar2.cs", + "Line": null, + "Column": null, + "MessageText": "Something went wrong again.", + "MessageHtml": "Something went wrong again.", + "MessageMarkdown": "Something went **wrong** again.", + "Priority": 300, + "PriorityName": "Warning", + "ProjectFileRelativePath": "src\/Foo\/Bar.csproj", + "ProjectName": "Bar", + "ProviderName": "Test Provider", + "ProviderType": "TestProvider", + "Rule": null, + "RuleUrl": null + } +] \ No newline at end of file diff --git a/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs b/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs index 918571a1d..61f75f75f 100644 --- a/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs +++ b/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs @@ -18,6 +18,7 @@ public IssueCheckerFixture(string messageText, string providerType, string provi this.ProjectName = "ProjectName"; this.AffectedFileRelativePath = @"src\source.file"; this.Line = 42; + this.Column = 23; this.MessageText = messageText; this.MessageHtml = "messageHtml"; this.MessageMarkdown = "messageMarkdown"; @@ -30,7 +31,7 @@ public IssueCheckerFixture(string messageText, string providerType, string provi .WithMessageInHtmlFormat(this.MessageHtml) .WithMessageInMarkdownFormat(this.MessageMarkdown) .InProject(this.ProjectFileRelativePath, this.ProjectName) - .InFile(this.AffectedFileRelativePath, this.Line) + .InFile(this.AffectedFileRelativePath, this.Line, this.Column) .OfRule(this.Rule, this.RuleUrl) .WithPriority(this.Priority, this.PriorityName); @@ -52,6 +53,8 @@ public IssueCheckerFixture(string messageText, string providerType, string provi public int Line { get; private set; } + public int Column { get; private set; } + public string MessageText { get; private set; } public string MessageHtml { get; private set; } diff --git a/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs b/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs index 2b8c8fddf..ecedcc733 100644 --- a/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs +++ b/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs @@ -148,6 +148,7 @@ public void Should_Throw_If_Issue_Is_Null() fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -175,6 +176,7 @@ public void Should_Not_Throw_If_All_Values_Are_The_Same() fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -206,6 +208,7 @@ public void Should_Throw_If_ProviderType_Is_Different(string expectedValue, stri fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -239,6 +242,7 @@ public void Should_Throw_If_ProviderName_Is_Different(string expectedValue, stri fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -273,6 +277,7 @@ public void Should_Throw_If_ProjectFileRelativePath_Is_Different(string expected fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -310,6 +315,7 @@ public void Should_Throw_If_ProjectName_Is_Different(string expectedValue, strin expectedValue, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -344,6 +350,7 @@ public void Should_Throw_If_AffectedFileRelativePath_Is_Different(string expecte fixture.ProjectName, expectedValue, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -367,7 +374,7 @@ public void Should_Throw_If_Line_Is_Different(int? expectedValue, int? actualVal var fixture = new IssueCheckerFixture(); var issue = fixture.IssueBuilder - .InFile(fixture.AffectedFileRelativePath, actualValue) + .InFile(fixture.AffectedFileRelativePath, actualValue, null) .Create(); // When @@ -380,6 +387,7 @@ public void Should_Throw_If_Line_Is_Different(int? expectedValue, int? actualVal fixture.ProjectName, fixture.AffectedFileRelativePath, expectedValue, + null, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -393,6 +401,43 @@ public void Should_Throw_If_Line_Is_Different(int? expectedValue, int? actualVal result.Message.ShouldStartWith("Expected issue.Line"); } + [Theory] + [InlineData(42, 23)] + [InlineData(null, 42)] + [InlineData(42, null)] + public void Should_Throw_If_Column_Is_Different(int? expectedValue, int? actualValue) + { + // Given + var fixture = new IssueCheckerFixture(); + var issue = + fixture.IssueBuilder + .InFile(fixture.AffectedFileRelativePath, fixture.Line, actualValue) + .Create(); + + // When + var result = Record.Exception(() => + IssueChecker.Check( + issue, + fixture.ProviderType, + fixture.ProviderName, + fixture.ProjectFileRelativePath, + fixture.ProjectName, + fixture.AffectedFileRelativePath, + fixture.Line, + expectedValue, + fixture.MessageText, + fixture.MessageHtml, + fixture.MessageMarkdown, + fixture.Priority, + fixture.PriorityName, + fixture.Rule, + fixture.RuleUrl)); + + // Then + result.ShouldBeOfType(); + result.Message.ShouldStartWith("Expected issue.Column"); + } + [Theory] [InlineData("Message", "Foo")] [InlineData(null, "Foo")] @@ -413,6 +458,7 @@ public void Should_Throw_If_MessageText_Is_Different(string expectedValue, strin fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, expectedValue, fixture.MessageHtml, fixture.MessageMarkdown, @@ -450,6 +496,7 @@ public void Should_Throw_If_MessageHtml_Is_Different(string expectedValue, strin fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, expectedValue, fixture.MessageMarkdown, @@ -487,6 +534,7 @@ public void Should_Throw_If_MessageMarkdown_Is_Different(string expectedValue, s fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, expectedValue, @@ -521,6 +569,7 @@ public void Should_Throw_If_Priority_Is_Different(IssuePriority expectedValue, I fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -558,6 +607,7 @@ public void Should_Throw_If_PriorityName_Is_Different(string expectedValue, stri fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -595,6 +645,7 @@ public void Should_Throw_If_Rule_Is_Different(string expectedValue, string actua fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -629,6 +680,7 @@ public void Should_Throw_If_RuleUrl_Is_Different(string expectedValue, string ac fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.Column, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, diff --git a/src/Cake.Issues/IIssue.cs b/src/Cake.Issues/IIssue.cs index 0a90ff793..979ccbd97 100644 --- a/src/Cake.Issues/IIssue.cs +++ b/src/Cake.Issues/IIssue.cs @@ -34,6 +34,12 @@ public interface IIssue /// int? Line { get; } + /// + /// Gets the column in the file where the issues has occurred. + /// null if the issue affects the whole file or an asssembly. + /// + int? Column { get; } + /// /// Gets the message of the issue in text format. /// diff --git a/src/Cake.Issues/IIssueComparer.cs b/src/Cake.Issues/IIssueComparer.cs index d7367fba3..ebdc5afaa 100644 --- a/src/Cake.Issues/IIssueComparer.cs +++ b/src/Cake.Issues/IIssueComparer.cs @@ -38,6 +38,9 @@ public IIssueComparer() /// /// /// + /// + /// + /// /// /// public IIssueComparer(bool compareOnlyPersistentProperties) @@ -63,6 +66,7 @@ public bool Equals(IIssue x, IIssue y) (x.ProjectName == y.ProjectName) && (this.compareOnlyPersistentProperties || x.AffectedFileRelativePath?.FullPath == y.AffectedFileRelativePath?.FullPath) && (this.compareOnlyPersistentProperties || x.Line == y.Line) && + (this.compareOnlyPersistentProperties || x.Column == y.Column) && (x.MessageText == y.MessageText) && (x.MessageHtml == y.MessageHtml) && (x.MessageMarkdown == y.MessageMarkdown) && @@ -105,6 +109,7 @@ public int GetHashCode(IIssue obj) obj.ProjectName, obj.AffectedFileRelativePath?.ToString(), obj.Line, + obj.Column, obj.MessageText, obj.MessageHtml, obj.MessageMarkdown, diff --git a/src/Cake.Issues/IIssueExtensions.cs b/src/Cake.Issues/IIssueExtensions.cs index 4c3c604bc..be030f94b 100644 --- a/src/Cake.Issues/IIssueExtensions.cs +++ b/src/Cake.Issues/IIssueExtensions.cs @@ -148,6 +148,10 @@ public static string FileName(this IIssue issue) /// The value of . /// /// + /// {Column} + /// The value of . + /// + /// /// {Rule} /// The value of . /// @@ -191,6 +195,7 @@ public static string ReplaceIssuePattern(this string pattern, IIssue issue) .Replace("{FileDirectory}", issue.FileDirectory()) .Replace("{FileName}", issue.FileName()) .Replace("{Line}", issue.Line?.ToString()) + .Replace("{Column}", issue.Column?.ToString()) .Replace("{Rule}", issue.Rule) .Replace("{RuleUrl}", issue.RuleUrl?.ToString()) .Replace("{MessageText}", issue.Message(IssueCommentFormat.PlainText)) diff --git a/src/Cake.Issues/Issue.cs b/src/Cake.Issues/Issue.cs index e699c512b..e0f7525b6 100644 --- a/src/Cake.Issues/Issue.cs +++ b/src/Cake.Issues/Issue.cs @@ -21,6 +21,8 @@ public class Issue : IIssue /// null or if issue is not related to a change in a file. /// The line in the file where the issues has occurred. /// null if the issue affects the whole file or an asssembly. + /// The column in the file where the issues has occurred. + /// null if the issue affects the whole file or an asssembly. /// The message of the issue in plain text format. /// The message of the issue in Html format. /// The message of the issue in Markdown format. @@ -39,6 +41,7 @@ public Issue( string projectName, string affectedFileRelativePath, int? line, + int? column, string messageText, string messageHtml, string messageMarkdown, @@ -50,6 +53,7 @@ public Issue( string providerName) { line?.NotNegativeOrZero(nameof(line)); + column?.NotNegativeOrZero(nameof(column)); messageText.NotNullOrWhiteSpace(nameof(messageText)); providerType.NotNullOrWhiteSpace(nameof(providerType)); providerName.NotNullOrWhiteSpace(nameof(providerName)); @@ -95,8 +99,14 @@ public Issue( throw new ArgumentOutOfRangeException(nameof(line), "Cannot specify a line while not specifying a file."); } + if (!line.HasValue && column.HasValue) + { + throw new ArgumentOutOfRangeException(nameof(column), $"Cannot specify a column while not specifying a line."); + } + this.ProjectName = projectName; this.Line = line; + this.Column = column; this.MessageText = messageText; this.MessageHtml = messageHtml; this.MessageMarkdown = messageMarkdown; @@ -120,6 +130,9 @@ public Issue( /// public int? Line { get; } + /// + public int? Column { get; } + /// public string MessageText { get; } diff --git a/src/Cake.Issues/IssueBuilder.cs b/src/Cake.Issues/IssueBuilder.cs index aee2041d6..a74e20252 100644 --- a/src/Cake.Issues/IssueBuilder.cs +++ b/src/Cake.Issues/IssueBuilder.cs @@ -16,6 +16,7 @@ public class IssueBuilder private string projectName; private string filePath; private int? line; + private int? column; private int? priority; private string priorityName; private string rule; @@ -185,6 +186,29 @@ public IssueBuilder InFile(string filePath, int? line) return this; } + /// + /// Sets the path to the file affected by the issue and the line and column in the file where the issues has occurred. + /// + /// The path to the file affacted by the issue. + /// The path needs to be relative to the repository root. + /// null or if issue is not related to a change in a file. + /// The line in the file where the issues has occurred. + /// null if the issue affects the whole file or an asssembly. + /// The column in the file where the issues has occurred. + /// null if the issue affects the whole file or an asssembly. + /// Issue Builder instance. + public IssueBuilder InFile(string filePath, int? line, int? column) + { + line?.NotNegativeOrZero(nameof(line)); + column?.NotNegativeOrZero(nameof(column)); + + this.filePath = filePath; + this.line = line; + this.column = column; + + return this; + } + /// /// Sets the priority of the issue. /// @@ -252,6 +276,7 @@ public IIssue Create() this.projectName, this.filePath, this.line, + this.column, this.messageText, this.messageHtml, this.messageMarkdown, diff --git a/src/Cake.Issues/Serialization/IssueDeserializationExtensions.cs b/src/Cake.Issues/Serialization/IssueDeserializationExtensions.cs index 1179b260c..2c59cdb5e 100644 --- a/src/Cake.Issues/Serialization/IssueDeserializationExtensions.cs +++ b/src/Cake.Issues/Serialization/IssueDeserializationExtensions.cs @@ -127,6 +127,8 @@ private static Issue DeserializeJsonDataToIssue(JsonData data) { case 2: return JsonMapper.ToObject(data.ToJson()).ToIssue(); + case 3: + return JsonMapper.ToObject(data.ToJson()).ToIssue(); default: throw new Exception($"Not supported issue serialization format {version}"); } diff --git a/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs b/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs index b66a33a31..031222759 100644 --- a/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs +++ b/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs @@ -70,20 +70,21 @@ public static void SerializeToJsonFile(this IEnumerable issues, FilePath } /// - /// Converts an to a . + /// Converts an to a . /// /// Issue which should be converted. /// Converted issue. - internal static SerializableIssueV2 ToSerializableIssue(this IIssue issue) + internal static SerializableIssueV3 ToSerializableIssue(this IIssue issue) { issue.NotNull(nameof(issue)); - return new SerializableIssueV2 + return new SerializableIssueV3 { ProjectFileRelativePath = issue.ProjectFileRelativePath?.FullPath, ProjectName = issue.ProjectName, AffectedFileRelativePath = issue.AffectedFileRelativePath?.FullPath, Line = issue.Line, + Column = issue.Column, MessageText = issue.MessageText, MessageMarkdown = issue.MessageMarkdown, MessageHtml = issue.MessageHtml, diff --git a/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs b/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs index 9b722e83c..997ff2aec 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs @@ -31,6 +31,7 @@ internal static Issue ToIssue(this SerializableIssue serializableIssue) serializableIssue.ProjectName, serializableIssue.AffectedFileRelativePath, serializableIssue.Line, + null, serializableIssue.Message, null, null, diff --git a/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs b/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs index 4ab0491f8..b23a307bb 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs @@ -31,6 +31,7 @@ internal static Issue ToIssue(this SerializableIssueV2 serializableIssue) serializableIssue.ProjectName, serializableIssue.AffectedFileRelativePath, serializableIssue.Line, + null, serializableIssue.MessageText, serializableIssue.MessageHtml, serializableIssue.MessageMarkdown, diff --git a/src/Cake.Issues/Serialization/SerializableIssueV3.cs b/src/Cake.Issues/Serialization/SerializableIssueV3.cs new file mode 100644 index 000000000..f3400f8d8 --- /dev/null +++ b/src/Cake.Issues/Serialization/SerializableIssueV3.cs @@ -0,0 +1,79 @@ +namespace Cake.Issues.Serialization +{ + using System.Runtime.Serialization; + + /// + /// Class for serializing and deserializing an instance. + /// + [DataContract] + internal class SerializableIssueV3 + { + /// + /// Gets the version of the serialization format. + /// + [DataMember] + public int Version + { + get + { + return 3; + } + } + + /// + [DataMember] + public string ProjectFileRelativePath { get; set; } + + /// + [DataMember] + public string ProjectName { get; set; } + + /// + [DataMember] + public string AffectedFileRelativePath { get; set; } + + /// + [DataMember] + public int? Line { get; set; } + + /// + [DataMember] + public int? Column { get; set; } + + /// + [DataMember] + public string MessageText { get; set; } + + /// + [DataMember] + public string MessageMarkdown { get; set; } + + /// + [DataMember] + public string MessageHtml { get; set; } + + /// + [DataMember] + public int? Priority { get; set; } + + /// + [DataMember] + public string PriorityName { get; set; } + + /// + [DataMember] + public string Rule { get; set; } + + /// + [DataMember] + public string RuleUrl { get; set; } + + /// + [DataMember] + public string ProviderType { get; set; } + + /// + [DataMember] + public string ProviderName { get; set; } + } +} diff --git a/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs b/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs new file mode 100644 index 000000000..e7169f7dc --- /dev/null +++ b/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs @@ -0,0 +1,48 @@ +namespace Cake.Issues.Serialization +{ + using System; + + /// + /// Extensions for . + /// + internal static class SerializableIssueV3Extensions + { + /// + /// Converts a to an . + /// + /// Issue which should be converted. + /// Converted issue. + internal static Issue ToIssue(this SerializableIssueV3 serializableIssue) + { +#pragma warning disable SA1123 // Do not place regions within elements + #region DupFinder Exclusion +#pragma warning restore SA1123 // Do not place regions within elements + + serializableIssue.NotNull(nameof(serializableIssue)); + + Uri ruleUrl = null; + if (!string.IsNullOrWhiteSpace(serializableIssue.RuleUrl)) + { + ruleUrl = new Uri(serializableIssue.RuleUrl); + } + + return new Issue( + serializableIssue.ProjectFileRelativePath, + serializableIssue.ProjectName, + serializableIssue.AffectedFileRelativePath, + serializableIssue.Line, + serializableIssue.Column, + serializableIssue.MessageText, + serializableIssue.MessageHtml, + serializableIssue.MessageMarkdown, + serializableIssue.Priority, + serializableIssue.PriorityName, + serializableIssue.Rule, + ruleUrl, + serializableIssue.ProviderType, + serializableIssue.ProviderName); + + #endregion + } + } +} From 8dca9412492b93305b7bdbdfaec69181336b47e1 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Tue, 30 Jun 2020 22:16:53 +0200 Subject: [PATCH 07/31] Add missing Fact on test --- src/Cake.Issues.Tests/IssueBuilderTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Cake.Issues.Tests/IssueBuilderTests.cs b/src/Cake.Issues.Tests/IssueBuilderTests.cs index 9e8ac88ef..8e28bf239 100644 --- a/src/Cake.Issues.Tests/IssueBuilderTests.cs +++ b/src/Cake.Issues.Tests/IssueBuilderTests.cs @@ -608,6 +608,7 @@ public void Should_Set_Line(int line) public sealed class TheInFileLineColumnMethod { + [Fact] public void Should_Throw_If_Line_Is_Negative() { // Given From 60382e0e04d10108e2465c3a2a83f27072ccaada Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Tue, 30 Jun 2020 22:39:51 +0200 Subject: [PATCH 08/31] Update to C# 8 --- src/Directory.Build.props | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/Directory.Build.props diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 000000000..a95ac958c --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,5 @@ + + + latest + + \ No newline at end of file From 06efd2e6f21d9c0693f8e3d39c60c2cb1dc8d219 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Wed, 1 Jul 2020 22:54:54 +0200 Subject: [PATCH 09/31] Update code for new C# 8 features --- src/Cake.Issues.Testing/IssueChecker.cs | 4 ++-- src/Cake.Issues/IIssueExtensions.cs | 16 ++++++---------- .../IssueDeserializationExtensions.cs | 13 +++++-------- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/Cake.Issues.Testing/IssueChecker.cs b/src/Cake.Issues.Testing/IssueChecker.cs index 6a83423f9..e432849d3 100644 --- a/src/Cake.Issues.Testing/IssueChecker.cs +++ b/src/Cake.Issues.Testing/IssueChecker.cs @@ -126,7 +126,7 @@ public static void Check( if (issue.ProjectFileRelativePath.ToString() != new FilePath(projectFileRelativePath).ToString()) { throw new Exception( - $"Expected issue.ProjectFileRelativePath to be '{projectFileRelativePath}' but was '{issue.ProjectFileRelativePath.ToString()}'."); + $"Expected issue.ProjectFileRelativePath to be '{projectFileRelativePath}' but was '{issue.ProjectFileRelativePath}'."); } if (!issue.ProjectFileRelativePath.IsRelative) @@ -155,7 +155,7 @@ public static void Check( if (issue.AffectedFileRelativePath.ToString() != new FilePath(affectedFileRelativePath).ToString()) { throw new Exception( - $"Expected issue.AffectedFileRelativePath to be '{affectedFileRelativePath}' but was '{issue.AffectedFileRelativePath.ToString()}'."); + $"Expected issue.AffectedFileRelativePath to be '{affectedFileRelativePath}' but was '{issue.AffectedFileRelativePath}'."); } if (!issue.AffectedFileRelativePath.IsRelative) diff --git a/src/Cake.Issues/IIssueExtensions.cs b/src/Cake.Issues/IIssueExtensions.cs index be030f94b..bdad7742b 100644 --- a/src/Cake.Issues/IIssueExtensions.cs +++ b/src/Cake.Issues/IIssueExtensions.cs @@ -20,17 +20,13 @@ public static string Message(this IIssue issue, IssueCommentFormat format) { issue.NotNull(nameof(issue)); - switch (format) + return format switch { - case IssueCommentFormat.PlainText: - return issue.MessageText; - case IssueCommentFormat.Html: - return !string.IsNullOrEmpty(issue.MessageHtml) ? issue.MessageHtml : issue.MessageText; - case IssueCommentFormat.Markdown: - return !string.IsNullOrEmpty(issue.MessageMarkdown) ? issue.MessageMarkdown : issue.MessageText; - default: - throw new ArgumentOutOfRangeException(nameof(format)); - } + IssueCommentFormat.PlainText => issue.MessageText, + IssueCommentFormat.Html => !string.IsNullOrEmpty(issue.MessageHtml) ? issue.MessageHtml : issue.MessageText, + IssueCommentFormat.Markdown => !string.IsNullOrEmpty(issue.MessageMarkdown) ? issue.MessageMarkdown : issue.MessageText, + _ => throw new ArgumentOutOfRangeException(nameof(format)), + }; } /// diff --git a/src/Cake.Issues/Serialization/IssueDeserializationExtensions.cs b/src/Cake.Issues/Serialization/IssueDeserializationExtensions.cs index 2c59cdb5e..ced6f66cd 100644 --- a/src/Cake.Issues/Serialization/IssueDeserializationExtensions.cs +++ b/src/Cake.Issues/Serialization/IssueDeserializationExtensions.cs @@ -123,15 +123,12 @@ private static Issue DeserializeJsonDataToIssue(JsonData data) if (data.ContainsKey("Version")) { var version = (int)data["Version"]; - switch (version) + return version switch { - case 2: - return JsonMapper.ToObject(data.ToJson()).ToIssue(); - case 3: - return JsonMapper.ToObject(data.ToJson()).ToIssue(); - default: - throw new Exception($"Not supported issue serialization format {version}"); - } + 2 => JsonMapper.ToObject(data.ToJson()).ToIssue(), + 3 => JsonMapper.ToObject(data.ToJson()).ToIssue(), + _ => throw new Exception($"Not supported issue serialization format {version}"), + }; } else { From c951dca1278d3568379421bfe360b77e336bbcdf Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Thu, 2 Jul 2020 08:33:24 +0200 Subject: [PATCH 10/31] Update code owners --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index da37e81da..44482aa47 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # These owners will be the default owners for everything in the repo and # will be requested for review when someone opens a pull request. -* @pascalberger @christianbumann @x-jokay @silanosa @georgesgoetz \ No newline at end of file +* @cake-contrib/team-bbt @x-jokay \ No newline at end of file From 7f9082c308e3bd3ace3843b5a2ee6b91200c972c Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Tue, 30 Jun 2020 22:07:15 +0200 Subject: [PATCH 11/31] (GH-179) Add run description to IIssue --- .gitattributes | 1 + src/Cake.Issues.Testing/IssueChecker.cs | 9 ++ src/Cake.Issues.Tests/IIssueComparerTests.cs | 76 ++++++++++ .../IIssueExtensionsTests.cs | 2 + src/Cake.Issues.Tests/IssueBuilderTests.cs | 62 ++++++++ src/Cake.Issues.Tests/IssueTests.cs | 142 ++++++++++++++++++ .../IssueDeserializationExtensionsTests.cs | 1 + .../IssueSerializationExtensionsTests.cs | 116 ++++++++++++++ src/Cake.Issues.Tests/Testfiles/issueV3.json | 1 + .../Testing/IssueCheckerFixture.cs | 4 + .../Testing/IssueCheckerTests.cs | 55 +++++++ src/Cake.Issues/IIssue.cs | 6 + src/Cake.Issues/IIssueComparer.cs | 3 + src/Cake.Issues/IIssueExtensions.cs | 5 + src/Cake.Issues/Issue.cs | 6 + src/Cake.Issues/IssueBuilder.cs | 16 ++ .../IssueSerializationExtensions.cs | 1 + .../SerializableIssueExtensions.cs | 1 + .../SerializableIssueV2Extensions.cs | 1 + .../Serialization/SerializableIssueV3.cs | 4 + .../SerializableIssueV3Extensions.cs | 1 + 21 files changed, 513 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..9cc496505 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.cs diff=csharp diff --git a/src/Cake.Issues.Testing/IssueChecker.cs b/src/Cake.Issues.Testing/IssueChecker.cs index e432849d3..ec1d9a8f7 100644 --- a/src/Cake.Issues.Testing/IssueChecker.cs +++ b/src/Cake.Issues.Testing/IssueChecker.cs @@ -41,6 +41,7 @@ public static void Check( issueToCheck, expectedIssue.ProviderType, expectedIssue.ProviderName, + expectedIssue.Run, expectedIssue.ProjectFileRelativePath?.ToString(), expectedIssue.ProjectName, expectedIssue.AffectedFileRelativePath?.ToString(), @@ -61,6 +62,7 @@ public static void Check( /// Issue which should be checked. /// Expected type of the issue provider. /// Expected human friendly name of the issue provider. + /// Expected name of the run which reported the issue. /// Expected relative path of the project file. /// null if the issue is not expected to be related to a project. /// Expected project name. @@ -86,6 +88,7 @@ public static void Check( IIssue issue, string providerType, string providerName, + string run, string projectFileRelativePath, string projectName, string affectedFileRelativePath, @@ -113,6 +116,12 @@ public static void Check( $"Expected issue.ProviderName to be '{providerName}' but was '{issue.ProviderName}'."); } + if (issue.Run != run) + { + throw new Exception( + $"Expected issue.Run to be '{run}' but was '{issue.Run}'."); + } + if (issue.ProjectFileRelativePath == null) { if (projectFileRelativePath != null) diff --git a/src/Cake.Issues.Tests/IIssueComparerTests.cs b/src/Cake.Issues.Tests/IIssueComparerTests.cs index b7a412f0a..675b7ce26 100644 --- a/src/Cake.Issues.Tests/IIssueComparerTests.cs +++ b/src/Cake.Issues.Tests/IIssueComparerTests.cs @@ -357,6 +357,25 @@ public void Should_Return_False_If_ProviderName_Is_Different() CompareIssues(issue1, issue2, false); } + [Fact] + public void Should_Return_False_If_Run_Is_Different() + { + // Given + var issue1 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .ForRun("run1") + .Create(); + var issue2 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .ForRun("run2") + .Create(); + + // When / Then + CompareIssues(issue1, issue2, false); + } + [Fact] public void Should_Return_True_If_Same_Reference() { @@ -711,6 +730,25 @@ public void Should_Return_True_If_ProviderName_Is_Same() CompareIssues(issue1, issue2, true); } + [Fact] + public void Should_Return_True_If_Run_Is_Same() + { + // Given + var issue1 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .ForRun("run") + .Create(); + var issue2 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .ForRun("run") + .Create(); + + // When / Then + CompareIssues(issue1, issue2, true); + } + [Fact] public void Should_Remove_Identical_Issues_From_List_Of_Issues() { @@ -1015,6 +1053,25 @@ public void Should_Return_False_If_ProviderName_Is_Different() CompareIssues(issue1, issue2, false); } + [Fact] + public void Should_Return_False_If_Run_Is_Different() + { + // Given + var issue1 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .ForRun("run1") + .Create(); + var issue2 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .ForRun("run2") + .Create(); + + // When / Then + CompareIssues(issue1, issue2, false); + } + [Fact] public void Should_Return_True_If_Same_Reference() { @@ -1463,6 +1520,25 @@ public void Should_Return_True_If_ProviderName_Is_Same() CompareIssues(issue1, issue2, true); } + [Fact] + public void Should_Return_True_If_Run_Is_Same() + { + // Given + var issue1 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .ForRun("run") + .Create(); + var issue2 = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .ForRun("run") + .Create(); + + // When / Then + CompareIssues(issue1, issue2, true); + } + [Fact] public void Should_Remove_Identical_Issues_From_List_Of_Issues() { diff --git a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs index 58db8d4a0..33bd8df6b 100644 --- a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs +++ b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs @@ -297,6 +297,7 @@ public void Should_Throw_If_Issue_Is_Null() [InlineData("{foo}", "{foo}")] [InlineData("foo {ProviderType} bar", "foo ProviderType Foo bar")] [InlineData("foo {ProviderName} bar", "foo ProviderName Foo bar")] + [InlineData("foo {Run} bar", "foo Run bar")] [InlineData("foo {Priority} bar", "foo 400 bar")] [InlineData("foo {PriorityName} bar", "foo Error bar")] [InlineData("foo {ProjectPath} bar", "foo src/Cake.Issues/Cake.Issues.csproj bar")] @@ -318,6 +319,7 @@ public void Should_Replace_Tokens(string pattern, string expectedResult) var issue = IssueBuilder .NewIssue("MessageText Foo", "ProviderType Foo", "ProviderName Foo") + .ForRun("Run") .WithMessageInHtmlFormat("MessageHtml Foo") .WithMessageInMarkdownFormat("MessageMarkdown Foo") .InFile(@"src/Cake.Issues/foo.cs", 42, 23) diff --git a/src/Cake.Issues.Tests/IssueBuilderTests.cs b/src/Cake.Issues.Tests/IssueBuilderTests.cs index 8e28bf239..af0d795c3 100644 --- a/src/Cake.Issues.Tests/IssueBuilderTests.cs +++ b/src/Cake.Issues.Tests/IssueBuilderTests.cs @@ -988,5 +988,67 @@ public void Should_Set_RuleUrl(string ruleUri) issue.RuleUrl.ToString().ShouldBe(ruleUri); } } + + public sealed class TheForRunMethod + { + [Fact] + public void Should_Throw_If_Run_Is_Null() + { + // Given + var fixture = new IssueBuilderFixture(); + string run = null; + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.ForRun(run)); + + // Then + result.IsArgumentNullException("run"); + } + + [Fact] + public void Should_Throw_If_Run_Is_Empty() + { + // Given + var fixture = new IssueBuilderFixture(); + string run = string.Empty; + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.ForRun(run)); + + // Then + result.IsArgumentException("run"); + } + + [Fact] + public void Should_Throw_If_Run_Is_WhiteSpace() + { + // Given + var fixture = new IssueBuilderFixture(); + string run = " "; + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.ForRun(run)); + + // Then + result.IsArgumentException("run"); + } + + [Theory] + [InlineData("run")] + public void Should_Set_Run(string run) + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.ForRun(run).Create(); + + // Then + issue.Run.ToString().ShouldBe(run); + } + } } } \ No newline at end of file diff --git a/src/Cake.Issues.Tests/IssueTests.cs b/src/Cake.Issues.Tests/IssueTests.cs index 84ddce339..e78939434 100644 --- a/src/Cake.Issues.Tests/IssueTests.cs +++ b/src/Cake.Issues.Tests/IssueTests.cs @@ -29,6 +29,7 @@ public void Should_Throw_If_Project_Path_Is_Invalid(string projectPath) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -45,6 +46,7 @@ public void Should_Throw_If_Project_Path_Is_Invalid(string projectPath) priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -72,6 +74,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string projectPath) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -88,6 +91,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string projectPath) priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -113,6 +117,7 @@ public void Should_Handle_Project_Paths_Which_Are_Null() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -129,6 +134,7 @@ public void Should_Handle_Project_Paths_Which_Are_Null() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -154,6 +160,7 @@ public void Should_Handle_Project_Paths_Which_Are_Empty() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -170,6 +177,7 @@ public void Should_Handle_Project_Paths_Which_Are_Empty() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -195,6 +203,7 @@ public void Should_Handle_Project_Paths_Which_Are_WhiteSpace() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -211,6 +220,7 @@ public void Should_Handle_Project_Paths_Which_Are_WhiteSpace() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -236,6 +246,7 @@ public void Should_Set_ProjectFileRelativePath(string projectPath) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -252,6 +263,7 @@ public void Should_Set_ProjectFileRelativePath(string projectPath) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -280,6 +292,7 @@ public void Should_Handle_Projects_Which_Are_Null() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -296,6 +309,7 @@ public void Should_Handle_Projects_Which_Are_Null() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -321,6 +335,7 @@ public void Should_Handle_Projects_Which_Are_Empty() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -337,6 +352,7 @@ public void Should_Handle_Projects_Which_Are_Empty() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -362,6 +378,7 @@ public void Should_Handle_Projects_Which_Are_WhiteSpace() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -378,6 +395,7 @@ public void Should_Handle_Projects_Which_Are_WhiteSpace() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -403,6 +421,7 @@ public void Should_Set_ProjectName(string projectName) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -419,6 +438,7 @@ public void Should_Set_ProjectName(string projectName) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -447,6 +467,7 @@ public void Should_Throw_If_File_Path_Is_Invalid(string filePath) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -463,6 +484,7 @@ public void Should_Throw_If_File_Path_Is_Invalid(string filePath) priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -490,6 +512,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string filePath) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -506,6 +529,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string filePath) priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -531,6 +555,7 @@ public void Should_Handle_File_Paths_Which_Are_Null() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -547,6 +572,7 @@ public void Should_Handle_File_Paths_Which_Are_Null() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -572,6 +598,7 @@ public void Should_Handle_File_Paths_Which_Are_Empty() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -588,6 +615,7 @@ public void Should_Handle_File_Paths_Which_Are_Empty() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -613,6 +641,7 @@ public void Should_Handle_File_Paths_Which_Are_WhiteSpace() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -629,6 +658,7 @@ public void Should_Handle_File_Paths_Which_Are_WhiteSpace() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -662,6 +692,7 @@ public void Should_Set_File_Path(string filePath, string expectedFilePath) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -678,6 +709,7 @@ public void Should_Set_File_Path(string filePath, string expectedFilePath) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -707,6 +739,7 @@ public void Should_Throw_If_Line_Is_Negative() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -723,6 +756,7 @@ public void Should_Throw_If_Line_Is_Negative() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -748,6 +782,7 @@ public void Should_Throw_If_Line_Is_Zero() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -764,6 +799,7 @@ public void Should_Throw_If_Line_Is_Zero() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -789,6 +825,7 @@ public void Should_Throw_If_Line_Is_Set_But_No_File() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -805,6 +842,7 @@ public void Should_Throw_If_Line_Is_Set_But_No_File() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -830,6 +868,7 @@ public void Should_Handle_Line_Which_Is_Null() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -846,6 +885,7 @@ public void Should_Handle_Line_Which_Is_Null() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -872,6 +912,7 @@ public void Should_Set_Line(int line) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -888,6 +929,7 @@ public void Should_Set_Line(int line) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -916,6 +958,7 @@ public void Should_Throw_If_Column_Is_Negative() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -932,6 +975,7 @@ public void Should_Throw_If_Column_Is_Negative() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -957,6 +1001,7 @@ public void Should_Throw_If_Column_Is_Zero() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -973,6 +1018,7 @@ public void Should_Throw_If_Column_Is_Zero() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -998,6 +1044,7 @@ public void Should_Throw_If_Column_Is_Set_But_No_Line() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -1014,6 +1061,7 @@ public void Should_Throw_If_Column_Is_Set_But_No_Line() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -1041,6 +1089,7 @@ public void Should_Set_Column(int? column) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1057,6 +1106,7 @@ public void Should_Set_Column(int? column) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1085,6 +1135,7 @@ public void Should_Throw_If_MessageText_Is_Null() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -1101,6 +1152,7 @@ public void Should_Throw_If_MessageText_Is_Null() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -1126,6 +1178,7 @@ public void Should_Throw_If_MessageText_Is_Empty() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -1142,6 +1195,7 @@ public void Should_Throw_If_MessageText_Is_Empty() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -1167,6 +1221,7 @@ public void Should_Throw_If_MessageText_Is_WhiteSpace() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -1183,6 +1238,7 @@ public void Should_Throw_If_MessageText_Is_WhiteSpace() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -1208,6 +1264,7 @@ public void Should_Set_MessageText(string messageText) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1224,6 +1281,7 @@ public void Should_Set_MessageText(string messageText) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1255,6 +1313,7 @@ public void Should_Set_MessageHtml(string messageHtml) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1271,6 +1330,7 @@ public void Should_Set_MessageHtml(string messageHtml) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1302,6 +1362,7 @@ public void Should_Set_MessageHtml(string messageMarkdown) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1318,6 +1379,7 @@ public void Should_Set_MessageHtml(string messageMarkdown) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1351,6 +1413,7 @@ public void Should_Set_Priority(int? priority) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1367,6 +1430,7 @@ public void Should_Set_Priority(int? priority) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1395,6 +1459,7 @@ public void Should_Handle_PriorityNames_Which_Are_Null() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1411,6 +1476,7 @@ public void Should_Handle_PriorityNames_Which_Are_Null() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1436,6 +1502,7 @@ public void Should_Handle_PriorityNames_Which_Are_Empty() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1452,6 +1519,7 @@ public void Should_Handle_PriorityNames_Which_Are_Empty() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1477,6 +1545,7 @@ public void Should_Handle_PriorityNames_Which_Are_WhiteSpace() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1493,6 +1562,7 @@ public void Should_Handle_PriorityNames_Which_Are_WhiteSpace() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1518,6 +1588,7 @@ public void Should_Set_Priority_Name(string priorityName) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1534,6 +1605,7 @@ public void Should_Set_Priority_Name(string priorityName) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1564,6 +1636,7 @@ public void Should_Set_Rule(string rule) var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1580,6 +1653,7 @@ public void Should_Set_Rule(string rule) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1608,6 +1682,7 @@ public void Should_Set_Rule_Url() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1624,6 +1699,7 @@ public void Should_Set_Rule_Url() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1649,6 +1725,7 @@ public void Should_Set_Rule_Url_If_Null() Uri ruleUri = null; var providerType = "ProviderType"; var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1665,6 +1742,7 @@ public void Should_Set_Rule_Url_If_Null() priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1673,6 +1751,54 @@ public void Should_Set_Rule_Url_If_Null() } } + public sealed class TheRunArgument + { + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("run")] + public void Should_Set_Run(string run) + { + // Given + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var column = 50; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var issue = + new Issue( + projectPath, + projectName, + filePath, + line, + column, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName); + + // Then + issue.Run.ShouldBe(run); + } + } + public sealed class TheProviderTypeArgument { [Fact] @@ -1693,6 +1819,7 @@ public void Should_Throw_If_Provider_Type_Is_Null() var ruleUri = new Uri("https://google.com"); string providerType = null; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -1709,6 +1836,7 @@ public void Should_Throw_If_Provider_Type_Is_Null() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -1734,6 +1862,7 @@ public void Should_Throw_If_Provider_Type_Is_Empty() var ruleUri = new Uri("https://google.com"); var providerType = string.Empty; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -1750,6 +1879,7 @@ public void Should_Throw_If_Provider_Type_Is_Empty() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -1775,6 +1905,7 @@ public void Should_Throw_If_Provider_Type_Is_WhiteSpace() var ruleUri = new Uri("https://google.com"); var providerType = " "; var providerName = "ProviderName"; + var run = "Run"; // When var result = Record.Exception(() => @@ -1791,6 +1922,7 @@ public void Should_Throw_If_Provider_Type_Is_WhiteSpace() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -1816,6 +1948,7 @@ public void Should_Set_ProviderType(string providerType) var rule = "Rule"; var ruleUri = new Uri("https://google.com"); var providerName = "ProviderName"; + var run = "Run"; // When var issue = @@ -1832,6 +1965,7 @@ public void Should_Set_ProviderType(string providerType) priorityName, rule, ruleUri, + run, providerType, providerName); @@ -1860,6 +1994,7 @@ public void Should_Throw_If_Provider_Name_Is_Null() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; string providerName = null; + var run = "Run"; // When var result = Record.Exception(() => @@ -1876,6 +2011,7 @@ public void Should_Throw_If_Provider_Name_Is_Null() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -1901,6 +2037,7 @@ public void Should_Throw_If_Provider_Name_Is_Empty() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = string.Empty; + var run = "Run"; // When var result = Record.Exception(() => @@ -1917,6 +2054,7 @@ public void Should_Throw_If_Provider_Name_Is_Empty() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -1942,6 +2080,7 @@ public void Should_Throw_If_Provider_Name_Is_WhiteSpace() var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; var providerName = " "; + var run = "Run"; // When var result = Record.Exception(() => @@ -1958,6 +2097,7 @@ public void Should_Throw_If_Provider_Name_Is_WhiteSpace() priorityName, rule, ruleUri, + run, providerType, providerName)); @@ -1983,6 +2123,7 @@ public void Should_Set_ProviderName(string providerName) var rule = "Rule"; var ruleUri = new Uri("https://google.com"); var providerType = "ProviderType"; + var run = "Run"; // When var issue = @@ -1999,6 +2140,7 @@ public void Should_Set_ProviderName(string providerName) priorityName, rule, ruleUri, + run, providerType, providerName); diff --git a/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs b/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs index 60646901a..3acdd342f 100644 --- a/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs +++ b/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs @@ -145,6 +145,7 @@ public void Should_Return_IssueV3() "Something went wrong.", "TestProvider", "Test Provider") + .ForRun("TestRun") .WithMessageInHtmlFormat("Something went wrong.") .WithMessageInMarkdownFormat("Something went **wrong**.") .InProject(@"src\Foo\Bar.csproj", "Bar") diff --git a/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs b/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs index 34bb7f391..7598cbbf9 100644 --- a/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs +++ b/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs @@ -113,6 +113,24 @@ public void Should_Give_Correct_Result_For_ProviderName_After_Roundtrip() result.ProviderName.ShouldBe(providerName); } + [Fact] + public void Should_Give_Correct_Result_For_Run_After_Roundtrip() + { + // Given + var run = "run"; + var issue = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .ForRun(run) + .Create(); + + // When + var result = issue.SerializeToJsonString().DeserializeToIssue(); + + // Then + result.Run.ShouldBe(run); + } + [Fact] public void Should_Give_Correct_Result_For_ProjectFileRelativePath_After_Roundtrip() { @@ -425,6 +443,34 @@ public void Should_Give_Correct_Result_For_ProviderName_After_Roundtrip() result.Last().ProviderName.ShouldBe(providerName2); } + [Fact] + public void Should_Give_Correct_Result_For_Run_After_Roundtrip() + { + // Given + var run1 = "run1"; + var run2 = "run2"; + var issues = + new List + { + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .ForRun(run1) + .Create(), + IssueBuilder + .NewIssue("message2", "providerType2", "providerName2") + .ForRun(run2) + .Create(), + }; + + // When + var result = issues.SerializeToJsonString().DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().Run.ShouldBe(run1); + result.Last().Run.ShouldBe(run2); + } + [Fact] public void Should_Give_Correct_Result_For_ProjectFileRelativePath_After_Roundtrip() { @@ -858,6 +904,36 @@ public void Should_Give_Correct_Result_For_ProviderName_After_Roundtrip() } } + [Fact] + public void Should_Give_Correct_Result_For_Run_After_Roundtrip() + { + // Given + var run = "run"; + var issue = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .ForRun(run) + .Create(); + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issue.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssue(); + + // Then + result.Run.ShouldBe(run); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_ProjectFileRelativePath_After_Roundtrip() { @@ -1353,6 +1429,46 @@ public void Should_Give_Correct_Result_For_ProviderName_After_Roundtrip() } } + [Fact] + public void Should_Give_Correct_Result_For_Run_After_Roundtrip() + { + // Given + var run1 = "run1"; + var run2 = "run2"; + var issues = + new List + { + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .ForRun(run1) + .Create(), + IssueBuilder + .NewIssue("message2", "providerType2", "providerName2") + .ForRun(run2) + .Create(), + }; + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issues.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().Run.ShouldBe(run1); + result.Last().Run.ShouldBe(run2); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_ProjectFileRelativePath_After_Roundtrip() { diff --git a/src/Cake.Issues.Tests/Testfiles/issueV3.json b/src/Cake.Issues.Tests/Testfiles/issueV3.json index fa44b3df7..731a61ce5 100644 --- a/src/Cake.Issues.Tests/Testfiles/issueV3.json +++ b/src/Cake.Issues.Tests/Testfiles/issueV3.json @@ -12,6 +12,7 @@ "ProjectName": "Bar", "ProviderName": "Test Provider", "ProviderType": "TestProvider", + "Run": "TestRun", "Rule": "Rule", "RuleUrl": "https://google.com" } \ No newline at end of file diff --git a/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs b/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs index 61f75f75f..81af41b19 100644 --- a/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs +++ b/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs @@ -14,6 +14,7 @@ public IssueCheckerFixture(string messageText, string providerType, string provi { this.ProviderType = providerType; this.ProviderName = providerName; + this.Run = "Test Run"; this.ProjectFileRelativePath = @"src\project.file"; this.ProjectName = "ProjectName"; this.AffectedFileRelativePath = @"src\source.file"; @@ -28,6 +29,7 @@ public IssueCheckerFixture(string messageText, string providerType, string provi this.RuleUrl = new Uri("https://google.com"); this.IssueBuilder + .ForRun(this.Run) .WithMessageInHtmlFormat(this.MessageHtml) .WithMessageInMarkdownFormat(this.MessageMarkdown) .InProject(this.ProjectFileRelativePath, this.ProjectName) @@ -45,6 +47,8 @@ public IssueCheckerFixture(string messageText, string providerType, string provi public string ProviderName { get; private set; } + public string Run { get; private set; } + public string ProjectFileRelativePath { get; private set; } public string ProjectName { get; private set; } diff --git a/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs b/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs index ecedcc733..1d2292465 100644 --- a/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs +++ b/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs @@ -144,6 +144,7 @@ public void Should_Throw_If_Issue_Is_Null() issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -172,6 +173,7 @@ public void Should_Not_Throw_If_All_Values_Are_The_Same() fixture.Issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -204,6 +206,7 @@ public void Should_Throw_If_ProviderType_Is_Different(string expectedValue, stri fixture.Issue, expectedValue, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -238,6 +241,7 @@ public void Should_Throw_If_ProviderName_Is_Different(string expectedValue, stri fixture.Issue, fixture.ProviderType, expectedValue, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -256,6 +260,45 @@ public void Should_Throw_If_ProviderName_Is_Different(string expectedValue, stri result.Message.ShouldStartWith("Expected issue.ProviderName"); } + [Theory] + [InlineData("Run", "Foo")] + [InlineData(null, "Foo")] + [InlineData("", "Foo")] + [InlineData(" ", "Foo")] + public void Should_Throw_If_Run_Is_Different(string expectedValue, string actualValue) + { + // Given + var fixture = new IssueCheckerFixture(); + var issue = + fixture.IssueBuilder + .ForRun(actualValue) + .Create(); + + // When + var result = Record.Exception(() => + IssueChecker.Check( + fixture.Issue, + fixture.ProviderType, + fixture.ProviderName, + expectedValue, + fixture.ProjectFileRelativePath, + fixture.ProjectName, + fixture.AffectedFileRelativePath, + fixture.Line, + fixture.Column, + fixture.MessageText, + fixture.MessageHtml, + fixture.MessageMarkdown, + fixture.Priority, + fixture.PriorityName, + fixture.Rule, + fixture.RuleUrl)); + + // Then + result.ShouldBeOfType(); + result.Message.ShouldStartWith("Expected issue.Run"); + } + [Theory] [InlineData(@"src\project.file", @"src\foo")] public void Should_Throw_If_ProjectFileRelativePath_Is_Different(string expectedValue, string actualValue) @@ -273,6 +316,7 @@ public void Should_Throw_If_ProjectFileRelativePath_Is_Different(string expected issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, expectedValue, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -311,6 +355,7 @@ public void Should_Throw_If_ProjectName_Is_Different(string expectedValue, strin issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, expectedValue, fixture.AffectedFileRelativePath, @@ -346,6 +391,7 @@ public void Should_Throw_If_AffectedFileRelativePath_Is_Different(string expecte issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, expectedValue, @@ -383,6 +429,7 @@ public void Should_Throw_If_Line_Is_Different(int? expectedValue, int? actualVal issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -420,6 +467,7 @@ public void Should_Throw_If_Column_Is_Different(int? expectedValue, int? actualV issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -454,6 +502,7 @@ public void Should_Throw_If_MessageText_Is_Different(string expectedValue, strin fixture.Issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -492,6 +541,7 @@ public void Should_Throw_If_MessageHtml_Is_Different(string expectedValue, strin fixture.Issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -530,6 +580,7 @@ public void Should_Throw_If_MessageMarkdown_Is_Different(string expectedValue, s fixture.Issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -565,6 +616,7 @@ public void Should_Throw_If_Priority_Is_Different(IssuePriority expectedValue, I issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -603,6 +655,7 @@ public void Should_Throw_If_PriorityName_Is_Different(string expectedValue, stri issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -641,6 +694,7 @@ public void Should_Throw_If_Rule_Is_Different(string expectedValue, string actua issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -676,6 +730,7 @@ public void Should_Throw_If_RuleUrl_Is_Different(string expectedValue, string ac issue, fixture.ProviderType, fixture.ProviderName, + fixture.Run, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, diff --git a/src/Cake.Issues/IIssue.cs b/src/Cake.Issues/IIssue.cs index 979ccbd97..3b8a45ce2 100644 --- a/src/Cake.Issues/IIssue.cs +++ b/src/Cake.Issues/IIssue.cs @@ -79,6 +79,12 @@ public interface IIssue /// Uri RuleUrl { get; } + /// + /// Gets the description of the run. + /// Can be null or if no run information is provided. + /// + string Run { get; } + /// /// Gets the type of the issue provider. /// diff --git a/src/Cake.Issues/IIssueComparer.cs b/src/Cake.Issues/IIssueComparer.cs index ebdc5afaa..7c5fb4a94 100644 --- a/src/Cake.Issues/IIssueComparer.cs +++ b/src/Cake.Issues/IIssueComparer.cs @@ -74,6 +74,7 @@ public bool Equals(IIssue x, IIssue y) (x.PriorityName == y.PriorityName) && (x.Rule == y.Rule) && (x.RuleUrl?.ToString() == y.RuleUrl?.ToString()) && + (x.Run == y.Run) && (x.ProviderType == y.ProviderType) && (x.ProviderName == y.ProviderName); } @@ -98,6 +99,7 @@ public int GetHashCode(IIssue obj) obj.PriorityName, obj.Rule, obj.RuleUrl, + obj.Run, obj.ProviderType, obj.ProviderName); } @@ -117,6 +119,7 @@ public int GetHashCode(IIssue obj) obj.PriorityName, obj.Rule, obj.RuleUrl, + obj.Run, obj.ProviderType, obj.ProviderName); } diff --git a/src/Cake.Issues/IIssueExtensions.cs b/src/Cake.Issues/IIssueExtensions.cs index bdad7742b..a9686ae87 100644 --- a/src/Cake.Issues/IIssueExtensions.cs +++ b/src/Cake.Issues/IIssueExtensions.cs @@ -156,6 +156,10 @@ public static string FileName(this IIssue issue) /// The value of . /// /// + /// {Run} + /// The value of . + /// + /// /// {MessageText} /// The value of . /// @@ -194,6 +198,7 @@ public static string ReplaceIssuePattern(this string pattern, IIssue issue) .Replace("{Column}", issue.Column?.ToString()) .Replace("{Rule}", issue.Rule) .Replace("{RuleUrl}", issue.RuleUrl?.ToString()) + .Replace("{Run}", issue.Run) .Replace("{MessageText}", issue.Message(IssueCommentFormat.PlainText)) .Replace("{MessageHtml}", issue.Message(IssueCommentFormat.Html)) .Replace("{MessageMarkdown}", issue.Message(IssueCommentFormat.Markdown)); diff --git a/src/Cake.Issues/Issue.cs b/src/Cake.Issues/Issue.cs index e0f7525b6..e723d5877 100644 --- a/src/Cake.Issues/Issue.cs +++ b/src/Cake.Issues/Issue.cs @@ -34,6 +34,7 @@ public class Issue : IIssue /// null or if issue has no specific rule ID. /// The URL containing information about the failing rule. /// null if no URL is available. + /// Gets the description of the run. /// The type of the issue provider. /// The human friendly name of the issue provider. public Issue( @@ -49,6 +50,7 @@ public Issue( string priorityName, string rule, Uri ruleUrl, + string run, string providerType, string providerName) { @@ -114,6 +116,7 @@ public Issue( this.PriorityName = priorityName; this.Rule = rule; this.RuleUrl = ruleUrl; + this.Run = run; this.ProviderType = providerType; this.ProviderName = providerName; } @@ -154,6 +157,9 @@ public Issue( /// public Uri RuleUrl { get; } + /// + public string Run { get; } + /// public string ProviderType { get; } diff --git a/src/Cake.Issues/IssueBuilder.cs b/src/Cake.Issues/IssueBuilder.cs index a74e20252..b7582f5f9 100644 --- a/src/Cake.Issues/IssueBuilder.cs +++ b/src/Cake.Issues/IssueBuilder.cs @@ -21,6 +21,7 @@ public class IssueBuilder private string priorityName; private string rule; private Uri ruleUrl; + private string run; /// /// Initializes a new instance of the class. @@ -264,6 +265,20 @@ public IssueBuilder OfRule(string name, Uri uri) return this; } + /// + /// Sets the name of the run where the issue was reported. + /// + /// The name of the run where the issue was reported. + /// Issue Builder instance. + public IssueBuilder ForRun(string run) + { + run.NotNullOrWhiteSpace(nameof(run)); + + this.run = run; + + return this; + } + /// /// Creates a new . /// @@ -284,6 +299,7 @@ public IIssue Create() this.priorityName, this.rule, this.ruleUrl, + this.run, this.providerType, this.providerName); } diff --git a/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs b/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs index 031222759..f56c42eb7 100644 --- a/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs +++ b/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs @@ -92,6 +92,7 @@ internal static SerializableIssueV3 ToSerializableIssue(this IIssue issue) PriorityName = issue.PriorityName, Rule = issue.Rule, RuleUrl = issue.RuleUrl?.ToString(), + Run = issue.Run, ProviderType = issue.ProviderType, ProviderName = issue.ProviderName, }; diff --git a/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs b/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs index 997ff2aec..17043daa5 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs @@ -39,6 +39,7 @@ internal static Issue ToIssue(this SerializableIssue serializableIssue) serializableIssue.PriorityName, serializableIssue.Rule, ruleUrl, + null, serializableIssue.ProviderType, serializableIssue.ProviderName); diff --git a/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs b/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs index b23a307bb..d1f9dc397 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs @@ -39,6 +39,7 @@ internal static Issue ToIssue(this SerializableIssueV2 serializableIssue) serializableIssue.PriorityName, serializableIssue.Rule, ruleUrl, + null, serializableIssue.ProviderType, serializableIssue.ProviderName); diff --git a/src/Cake.Issues/Serialization/SerializableIssueV3.cs b/src/Cake.Issues/Serialization/SerializableIssueV3.cs index f3400f8d8..749dc7cdc 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV3.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV3.cs @@ -75,5 +75,9 @@ public int Version /// [DataMember] public string ProviderName { get; set; } + + /// + [DataMember] + public string Run { get; set; } } } diff --git a/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs b/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs index e7169f7dc..ffa3f222f 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs @@ -39,6 +39,7 @@ internal static Issue ToIssue(this SerializableIssueV3 serializableIssue) serializableIssue.PriorityName, serializableIssue.Rule, ruleUrl, + serializableIssue.Run, serializableIssue.ProviderType, serializableIssue.ProviderName); From 7788192f7ee5a92f41ac2ab99d42468b5b03198e Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Tue, 30 Jun 2020 22:37:18 +0200 Subject: [PATCH 12/31] (GH-179) Add option to set pass run information to ReadIssues aliases --- src/Cake.Issues.Tests/IssueReaderTests.cs | 43 +++++++++++++++++++++++ src/Cake.Issues.Tests/IssuesFixture.cs | 2 +- src/Cake.Issues/IIssue.cs | 4 +-- src/Cake.Issues/Issue.cs | 2 +- src/Cake.Issues/IssuesReader.cs | 6 ++-- src/Cake.Issues/ReadIssuesSettings.cs | 5 +++ 6 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/Cake.Issues.Tests/IssueReaderTests.cs b/src/Cake.Issues.Tests/IssueReaderTests.cs index 6a6696d62..91d652468 100644 --- a/src/Cake.Issues.Tests/IssueReaderTests.cs +++ b/src/Cake.Issues.Tests/IssueReaderTests.cs @@ -288,6 +288,49 @@ public void Should_Read_Correct_Number_Of_Issues_From_Multiple_Providers() issues.ShouldContain(issue3); issues.ShouldContain(issue4); } + + [Fact] + public void Should_Set_Run_Property() + { + // Given + var issue1 = + IssueBuilder + .NewIssue("Foo", "ProviderTypeFoo", "ProviderNameFoo") + .InFile(@"src\Cake.Issues.Tests\FakeIssueProvider.cs", 10) + .OfRule("Foo") + .WithPriority(IssuePriority.Warning) + .Create(); + var issue2 = + IssueBuilder + .NewIssue("Bar", "ProviderTypeBar", "ProviderNameBar") + .InFile(@"src\Cake.Issues.Tests\FakeIssueProvider.cs", 12) + .OfRule("Bar") + .WithPriority(IssuePriority.Warning) + .Create(); + var fixture = new IssuesFixture(); + fixture.IssueProviders.Clear(); + fixture.IssueProviders.Add( + new FakeIssueProvider( + fixture.Log, + new List + { + issue1, + issue2, + })); + var run = "Run"; + fixture.Settings.Run = run; + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(2); + issues.ShouldContain(issue1); + issue1.Run.ShouldBe(run); + issues.ShouldContain(issue2); + issue2.Run.ShouldBe(run); + } + } } } \ No newline at end of file diff --git a/src/Cake.Issues.Tests/IssuesFixture.cs b/src/Cake.Issues.Tests/IssuesFixture.cs index eecba2799..810ca5076 100644 --- a/src/Cake.Issues.Tests/IssuesFixture.cs +++ b/src/Cake.Issues.Tests/IssuesFixture.cs @@ -20,7 +20,7 @@ public IssuesFixture() public IList IssueProviders { get; set; } - public RepositorySettings Settings { get; set; } + public ReadIssuesSettings Settings { get; set; } public IEnumerable ReadIssues() { diff --git a/src/Cake.Issues/IIssue.cs b/src/Cake.Issues/IIssue.cs index 3b8a45ce2..2a5171301 100644 --- a/src/Cake.Issues/IIssue.cs +++ b/src/Cake.Issues/IIssue.cs @@ -80,10 +80,10 @@ public interface IIssue Uri RuleUrl { get; } /// - /// Gets the description of the run. + /// Gets or sets the description of the run. /// Can be null or if no run information is provided. /// - string Run { get; } + string Run { get; set; } /// /// Gets the type of the issue provider. diff --git a/src/Cake.Issues/Issue.cs b/src/Cake.Issues/Issue.cs index e723d5877..45acc820b 100644 --- a/src/Cake.Issues/Issue.cs +++ b/src/Cake.Issues/Issue.cs @@ -158,7 +158,7 @@ public Issue( public Uri RuleUrl { get; } /// - public string Run { get; } + public string Run { get; set; } /// public string ProviderType { get; } diff --git a/src/Cake.Issues/IssuesReader.cs b/src/Cake.Issues/IssuesReader.cs index 7751cbc34..d0a9372ec 100644 --- a/src/Cake.Issues/IssuesReader.cs +++ b/src/Cake.Issues/IssuesReader.cs @@ -11,7 +11,7 @@ public class IssuesReader { private readonly ICakeLog log; private readonly List issueProviders = new List(); - private readonly RepositorySettings settings; + private readonly ReadIssuesSettings settings; /// /// Initializes a new instance of the class. @@ -22,7 +22,7 @@ public class IssuesReader public IssuesReader( ICakeLog log, IEnumerable issueProviders, - RepositorySettings settings) + ReadIssuesSettings settings) { log.NotNull(nameof(log)); settings.NotNull(nameof(settings)); @@ -59,6 +59,8 @@ public IEnumerable ReadIssues() currentIssues.Count, providerName); + currentIssues.ForEach(x => x.Run = this.settings.Run); + issues.AddRange(currentIssues); } else diff --git a/src/Cake.Issues/ReadIssuesSettings.cs b/src/Cake.Issues/ReadIssuesSettings.cs index d3c52dcec..f535a9b08 100644 --- a/src/Cake.Issues/ReadIssuesSettings.cs +++ b/src/Cake.Issues/ReadIssuesSettings.cs @@ -15,5 +15,10 @@ public ReadIssuesSettings(DirectoryPath repositoryRoot) : base(repositoryRoot) { } + + /// + /// Gets or sets the name of the run. + /// + public string Run { get; set; } } } From aaf5337ed51f43fba3a3cb654bf7a1e06a47fcbc Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Wed, 1 Jul 2020 22:27:47 +0200 Subject: [PATCH 13/31] (GH-170) Add identifier to IIssue --- src/Cake.Issues.Testing/IssueChecker.cs | 9 + .../IIssueExtensionsTests.cs | 3 +- src/Cake.Issues.Tests/IssueBuilderFixture.cs | 6 +- src/Cake.Issues.Tests/IssueBuilderTests.cs | 614 +++++++++++++++++- src/Cake.Issues.Tests/IssueReaderTests.cs | 1 - src/Cake.Issues.Tests/IssueTests.cs | 279 ++++++++ .../IssueDeserializationExtensionsTests.cs | 3 + .../IssueSerializationExtensionsTests.cs | 110 ++++ src/Cake.Issues.Tests/Testfiles/issueV3.json | 1 + src/Cake.Issues.Tests/Testfiles/issuesV3.json | 2 + .../Testing/IssueCheckerFixture.cs | 9 +- .../Testing/IssueCheckerTests.cs | 59 +- src/Cake.Issues/Aliases.NewIssue.cs | 51 +- src/Cake.Issues/IIssue.cs | 6 + src/Cake.Issues/IIssueComparer.cs | 3 + src/Cake.Issues/IIssueExtensions.cs | 5 + src/Cake.Issues/Issue.cs | 8 + src/Cake.Issues/IssueBuilder.cs | 85 ++- .../IssueSerializationExtensions.cs | 1 + .../SerializableIssueExtensions.cs | 1 + .../SerializableIssueV2Extensions.cs | 1 + .../Serialization/SerializableIssueV3.cs | 4 + .../SerializableIssueV3Extensions.cs | 1 + 23 files changed, 1238 insertions(+), 24 deletions(-) diff --git a/src/Cake.Issues.Testing/IssueChecker.cs b/src/Cake.Issues.Testing/IssueChecker.cs index ec1d9a8f7..2d42e8d64 100644 --- a/src/Cake.Issues.Testing/IssueChecker.cs +++ b/src/Cake.Issues.Testing/IssueChecker.cs @@ -42,6 +42,7 @@ public static void Check( expectedIssue.ProviderType, expectedIssue.ProviderName, expectedIssue.Run, + expectedIssue.Identifier, expectedIssue.ProjectFileRelativePath?.ToString(), expectedIssue.ProjectName, expectedIssue.AffectedFileRelativePath?.ToString(), @@ -63,6 +64,7 @@ public static void Check( /// Expected type of the issue provider. /// Expected human friendly name of the issue provider. /// Expected name of the run which reported the issue. + /// Expected identifier of the issue. /// Expected relative path of the project file. /// null if the issue is not expected to be related to a project. /// Expected project name. @@ -89,6 +91,7 @@ public static void Check( string providerType, string providerName, string run, + string identifier, string projectFileRelativePath, string projectName, string affectedFileRelativePath, @@ -122,6 +125,12 @@ public static void Check( $"Expected issue.Run to be '{run}' but was '{issue.Run}'."); } + if (issue.Identifier != identifier) + { + throw new Exception( + $"Expected issue.Identifier to be '{identifier}' but was '{issue.Identifier}'."); + } + if (issue.ProjectFileRelativePath == null) { if (projectFileRelativePath != null) diff --git a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs index 33bd8df6b..dc2bc48c9 100644 --- a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs +++ b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs @@ -298,6 +298,7 @@ public void Should_Throw_If_Issue_Is_Null() [InlineData("foo {ProviderType} bar", "foo ProviderType Foo bar")] [InlineData("foo {ProviderName} bar", "foo ProviderName Foo bar")] [InlineData("foo {Run} bar", "foo Run bar")] + [InlineData("foo {Identifier} bar", "foo Identifier Foo bar")] [InlineData("foo {Priority} bar", "foo 400 bar")] [InlineData("foo {PriorityName} bar", "foo Error bar")] [InlineData("foo {ProjectPath} bar", "foo src/Cake.Issues/Cake.Issues.csproj bar")] @@ -318,7 +319,7 @@ public void Should_Replace_Tokens(string pattern, string expectedResult) // Given var issue = IssueBuilder - .NewIssue("MessageText Foo", "ProviderType Foo", "ProviderName Foo") + .NewIssue("Identifier Foo", "MessageText Foo", "ProviderType Foo", "ProviderName Foo") .ForRun("Run") .WithMessageInHtmlFormat("MessageHtml Foo") .WithMessageInMarkdownFormat("MessageMarkdown Foo") diff --git a/src/Cake.Issues.Tests/IssueBuilderFixture.cs b/src/Cake.Issues.Tests/IssueBuilderFixture.cs index 7b5e1cbc0..c81ff3cf1 100644 --- a/src/Cake.Issues.Tests/IssueBuilderFixture.cs +++ b/src/Cake.Issues.Tests/IssueBuilderFixture.cs @@ -3,14 +3,14 @@ internal class IssueBuilderFixture { public IssueBuilderFixture() - : this("Message", "ProviderType", "ProviderName") + : this("Identifier", "Message", "ProviderType", "ProviderName") { } - public IssueBuilderFixture(string messageText, string providerType, string providerName) + public IssueBuilderFixture(string identifier, string messageText, string providerType, string providerName) { this.IssueBuilder = - IssueBuilder.NewIssue(messageText, providerType, providerName); + IssueBuilder.NewIssue(identifier, messageText, providerType, providerName); } public IssueBuilder IssueBuilder { get; private set; } diff --git a/src/Cake.Issues.Tests/IssueBuilderTests.cs b/src/Cake.Issues.Tests/IssueBuilderTests.cs index af0d795c3..c12f6e5e5 100644 --- a/src/Cake.Issues.Tests/IssueBuilderTests.cs +++ b/src/Cake.Issues.Tests/IssueBuilderTests.cs @@ -8,7 +8,7 @@ public sealed class IssueBuilderTests { - public sealed class TheNewIssueMethod + public sealed class TheNewIssueMethodWithMessageAsIdentifier { [Fact] public void Should_Throw_If_Message_Is_Null() @@ -153,9 +153,364 @@ public void Should_Throw_If_ProviderName_Is_WhiteSpace() // Then result.IsArgumentOutOfRangeException("providerName"); } + + [Fact] + public void Should_Set_Identifier() + { + // Given + var message = "Message"; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = + IssueBuilder + .NewIssue(message, providerType, providerName) + .Create(); + + // Then + result.Identifier.ShouldBe(message); + } + + [Fact] + public void Should_Set_Message() + { + // Given + var message = "Message"; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = + IssueBuilder + .NewIssue(message, providerType, providerName) + .Create(); + + // Then + result.MessageText.ShouldBe(message); + } + + [Fact] + public void Should_Set_ProviderType() + { + // Given + var message = "Message"; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = + IssueBuilder + .NewIssue(message, providerType, providerName) + .Create(); + + // Then + result.ProviderType.ShouldBe(providerType); + } + + [Fact] + public void Should_Set_ProviderName() + { + // Given + var message = "Message"; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = + IssueBuilder + .NewIssue(message, providerType, providerName) + .Create(); + + // Then + result.ProviderName.ShouldBe(providerName); + } } - public sealed class TheNewIssueOfTMethod + public sealed class TheNewIssueMethod + { + [Fact] + public void Should_Throw_If_Identifier_Is_Null() + { + // Given + string identifier = null; + var message = "Message"; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentNullException("identifier"); + } + + [Fact] + public void Should_Throw_If_Identifier_Is_Empty() + { + // Given + var identifier = string.Empty; + var message = "Message"; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentOutOfRangeException("identifier"); + } + + [Fact] + public void Should_Throw_If_Identifier_Is_WhiteSpace() + { + // Given + var identifier = " "; + var message = "Message"; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentOutOfRangeException("identifier"); + } + + [Fact] + public void Should_Throw_If_Message_Is_Null() + { + // Given + var identifier = "Identifier"; + string message = null; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentNullException("message"); + } + + [Fact] + public void Should_Throw_If_Message_Is_Empty() + { + // Given + var identifier = "Identifier"; + var message = string.Empty; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentOutOfRangeException("message"); + } + + [Fact] + public void Should_Throw_If_Message_Is_WhiteSpace() + { + // Given + var identifier = "Identifier"; + var message = " "; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentOutOfRangeException("message"); + } + + [Fact] + public void Should_Throw_If_ProviderType_Is_Null() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + string providerType = null; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentNullException("providerType"); + } + + [Fact] + public void Should_Throw_If_ProviderType_Is_Empty() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var providerType = string.Empty; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentOutOfRangeException("providerType"); + } + + [Fact] + public void Should_Throw_If_ProviderType_Is_WhiteSpace() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var providerType = " "; + var providerName = "ProviderName"; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentOutOfRangeException("providerType"); + } + + [Fact] + public void Should_Throw_If_ProviderName_Is_Null() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var providerType = "ProviderType"; + string providerName = null; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentNullException("providerName"); + } + + [Fact] + public void Should_Throw_If_ProviderName_Is_Empty() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var providerType = "ProviderType"; + var providerName = string.Empty; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentOutOfRangeException("providerName"); + } + + [Fact] + public void Should_Throw_If_ProviderName_Is_WhiteSpace() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var providerType = "ProviderType"; + var providerName = " "; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, providerType, providerName)); + + // Then + result.IsArgumentOutOfRangeException("providerName"); + } + + [Fact] + public void Should_Set_Identifier() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = + IssueBuilder + .NewIssue(identifier, message, providerType, providerName) + .Create(); + + // Then + result.Identifier.ShouldBe(identifier); + } + + [Fact] + public void Should_Set_Message() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = + IssueBuilder + .NewIssue(identifier, message, providerType, providerName) + .Create(); + + // Then + result.MessageText.ShouldBe(message); + } + + [Fact] + public void Should_Set_ProviderType() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = + IssueBuilder + .NewIssue(identifier, message, providerType, providerName) + .Create(); + + // Then + result.ProviderType.ShouldBe(providerType); + } + + [Fact] + public void Should_Set_ProviderName() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var providerType = "ProviderType"; + var providerName = "ProviderName"; + + // When + var result = + IssueBuilder + .NewIssue(identifier, message, providerType, providerName) + .Create(); + + // Then + result.ProviderName.ShouldBe(providerName); + } + } + + public sealed class TheNewIssueOfTMethodWithMessageAsIdentifier { [Fact] public void Should_Throw_If_Message_Is_Null() @@ -216,6 +571,261 @@ public void Should_Throw_If_IssueProvider_Is_Null() // Then result.IsArgumentNullException("issueProvider"); } + + [Fact] + public void Should_Set_Identifier() + { + // Given + var message = "Message"; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = + IssueBuilder + .NewIssue(message, issueProvider) + .Create(); + + // Then + result.Identifier.ShouldBe(message); + } + + [Fact] + public void Should_Set_Message() + { + // Given + var message = "Message"; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = + IssueBuilder + .NewIssue(message, issueProvider) + .Create(); + + // Then + result.MessageText.ShouldBe(message); + } + + [Fact] + public void Should_Set_ProviderType() + { + // Given + var message = "Message"; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = + IssueBuilder + .NewIssue(message, issueProvider) + .Create(); + + // Then + result.ProviderType.ShouldBe(issueProvider.GetType().FullName); + } + + [Fact] + public void Should_Set_ProviderName() + { + // Given + var message = "Message"; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = + IssueBuilder + .NewIssue(message, issueProvider) + .Create(); + + // Then + result.ProviderName.ShouldBe(issueProvider.ProviderName); + } + } + + public sealed class TheNewIssueOfTMethod + { + [Fact] + public void Should_Throw_If_Identifier_Is_Null() + { + // Given + string identifier = null; + var message = "Message"; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, issueProvider)); + + // Then + result.IsArgumentNullException("identifier"); + } + + [Fact] + public void Should_Throw_If_Identifier_Is_Empty() + { + // Given + var identifier = string.Empty; + var message = "Message"; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, issueProvider)); + + // Then + result.IsArgumentOutOfRangeException("identifier"); + } + + [Fact] + public void Should_Throw_If_Identifier_Is_WhiteSpace() + { + // Given + var identifier = " "; + var message = "Message"; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, issueProvider)); + + // Then + result.IsArgumentOutOfRangeException("identifier"); + } + + [Fact] + public void Should_Throw_If_Message_Is_Null() + { + // Given + var identifier = "Identifier"; + string message = null; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, issueProvider)); + + // Then + result.IsArgumentNullException("message"); + } + + [Fact] + public void Should_Throw_If_Message_Is_Empty() + { + // Given + var identifier = "Identifier"; + var message = string.Empty; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, issueProvider)); + + // Then + result.IsArgumentOutOfRangeException("message"); + } + + [Fact] + public void Should_Throw_If_Message_Is_WhiteSpace() + { + // Given + var identifier = "Identifier"; + var message = " "; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, issueProvider)); + + // Then + result.IsArgumentOutOfRangeException("message"); + } + + [Fact] + public void Should_Throw_If_IssueProvider_Is_Null() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + IIssueProvider issueProvider = null; + + // When + var result = Record.Exception(() => + IssueBuilder.NewIssue(identifier, message, issueProvider)); + + // Then + result.IsArgumentNullException("issueProvider"); + } + + [Fact] + public void Should_Set_Identifier() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = + IssueBuilder + .NewIssue(identifier, message, issueProvider) + .Create(); + + // Then + result.Identifier.ShouldBe(identifier); + } + + [Fact] + public void Should_Set_Message() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = + IssueBuilder + .NewIssue(identifier, message, issueProvider) + .Create(); + + // Then + result.MessageText.ShouldBe(message); + } + + [Fact] + public void Should_Set_ProviderType() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = + IssueBuilder + .NewIssue(identifier, message, issueProvider) + .Create(); + + // Then + result.ProviderType.ShouldBe(issueProvider.GetType().FullName); + } + + [Fact] + public void Should_Set_ProviderName() + { + // Given + var identifier = "Identifier"; + var message = "Message"; + var issueProvider = new FakeIssueProvider(new FakeLog()); + + // When + var result = + IssueBuilder + .NewIssue(identifier, message, issueProvider) + .Create(); + + // Then + result.ProviderName.ShouldBe(issueProvider.ProviderName); + } } public sealed class TheInProjectFileMethod diff --git a/src/Cake.Issues.Tests/IssueReaderTests.cs b/src/Cake.Issues.Tests/IssueReaderTests.cs index 91d652468..a75cb5093 100644 --- a/src/Cake.Issues.Tests/IssueReaderTests.cs +++ b/src/Cake.Issues.Tests/IssueReaderTests.cs @@ -330,7 +330,6 @@ public void Should_Set_Run_Property() issues.ShouldContain(issue2); issue2.Run.ShouldBe(run); } - } } } \ No newline at end of file diff --git a/src/Cake.Issues.Tests/IssueTests.cs b/src/Cake.Issues.Tests/IssueTests.cs index e78939434..bad01c7ad 100644 --- a/src/Cake.Issues.Tests/IssueTests.cs +++ b/src/Cake.Issues.Tests/IssueTests.cs @@ -9,6 +9,189 @@ public sealed class IssueTests { public sealed class TheCtor { + public sealed class TheIdentifierArgument + { + [Fact] + public void Should_Throw_If_Identifier_Is_Null() + { + // Given + string identifier = null; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var column = 50; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var result = Record.Exception(() => + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + column, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName)); + + // Then + result.IsArgumentNullException("identifier"); + } + + [Fact] + public void Should_Throw_If_Identifier_Is_Empty() + { + // Given + var identifier = string.Empty; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var column = 50; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var result = Record.Exception(() => + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + column, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("identifier"); + } + + [Fact] + public void Should_Throw_If_Identifier_Is_WhiteSpace() + { + // Given + var identifier = " "; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var column = 50; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var result = Record.Exception(() => + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + column, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("identifier"); + } + + [Theory] + [InlineData("identifier")] + public void Should_Set_Identifier(string identifier) + { + // Given + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var column = 50; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var issue = + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + column, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName); + + // Then + issue.Identifier.ShouldBe(identifier); + } + } + public sealed class TheProjectFileRelativePathArgument { [Theory] @@ -16,6 +199,7 @@ public sealed class TheProjectFileRelativePathArgument public void Should_Throw_If_Project_Path_Is_Invalid(string projectPath) { // Given + var identifier = "identifier"; var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 100; @@ -34,6 +218,7 @@ public void Should_Throw_If_Project_Path_Is_Invalid(string projectPath) // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -61,6 +246,7 @@ public void Should_Throw_If_Project_Path_Is_Invalid(string projectPath) public void Should_Throw_If_File_Path_Is_Absolute(string projectPath) { // Given + var identifier = "identifier"; var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 100; @@ -79,6 +265,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string projectPath) // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -103,6 +290,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string projectPath) public void Should_Handle_Project_Paths_Which_Are_Null() { // Given + var identifier = "identifier"; string projectPath = null; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -122,6 +310,7 @@ public void Should_Handle_Project_Paths_Which_Are_Null() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -146,6 +335,7 @@ public void Should_Handle_Project_Paths_Which_Are_Null() public void Should_Handle_Project_Paths_Which_Are_Empty() { // Given + var identifier = "identifier"; var projectPath = string.Empty; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -165,6 +355,7 @@ public void Should_Handle_Project_Paths_Which_Are_Empty() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -189,6 +380,7 @@ public void Should_Handle_Project_Paths_Which_Are_Empty() public void Should_Handle_Project_Paths_Which_Are_WhiteSpace() { // Given + var identifier = "identifier"; var projectPath = " "; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -208,6 +400,7 @@ public void Should_Handle_Project_Paths_Which_Are_WhiteSpace() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -233,6 +426,7 @@ public void Should_Handle_Project_Paths_Which_Are_WhiteSpace() public void Should_Set_ProjectFileRelativePath(string projectPath) { // Given + var identifier = "identifier"; var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; @@ -251,6 +445,7 @@ public void Should_Set_ProjectFileRelativePath(string projectPath) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -278,6 +473,7 @@ public sealed class TheProjectNameArgument public void Should_Handle_Projects_Which_Are_Null() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; string projectName = null; var filePath = @"src\foo.cs"; @@ -297,6 +493,7 @@ public void Should_Handle_Projects_Which_Are_Null() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -321,6 +518,7 @@ public void Should_Handle_Projects_Which_Are_Null() public void Should_Handle_Projects_Which_Are_Empty() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = string.Empty; var filePath = @"src\foo.cs"; @@ -340,6 +538,7 @@ public void Should_Handle_Projects_Which_Are_Empty() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -364,6 +563,7 @@ public void Should_Handle_Projects_Which_Are_Empty() public void Should_Handle_Projects_Which_Are_WhiteSpace() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = " "; var filePath = @"src\foo.cs"; @@ -383,6 +583,7 @@ public void Should_Handle_Projects_Which_Are_WhiteSpace() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -408,6 +609,7 @@ public void Should_Handle_Projects_Which_Are_WhiteSpace() public void Should_Set_ProjectName(string projectName) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var filePath = @"src\foo.cs"; var line = 10; @@ -426,6 +628,7 @@ public void Should_Set_ProjectName(string projectName) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -454,6 +657,7 @@ public sealed class TheAffectedFileRelativePathArgument public void Should_Throw_If_File_Path_Is_Invalid(string filePath) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var line = 100; @@ -472,6 +676,7 @@ public void Should_Throw_If_File_Path_Is_Invalid(string filePath) // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -499,6 +704,7 @@ public void Should_Throw_If_File_Path_Is_Invalid(string filePath) public void Should_Throw_If_File_Path_Is_Absolute(string filePath) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var line = 100; @@ -517,6 +723,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string filePath) // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -541,6 +748,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string filePath) public void Should_Handle_File_Paths_Which_Are_Null() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; string filePath = null; @@ -560,6 +768,7 @@ public void Should_Handle_File_Paths_Which_Are_Null() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -584,6 +793,7 @@ public void Should_Handle_File_Paths_Which_Are_Null() public void Should_Handle_File_Paths_Which_Are_Empty() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = string.Empty; @@ -603,6 +813,7 @@ public void Should_Handle_File_Paths_Which_Are_Empty() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -627,6 +838,7 @@ public void Should_Handle_File_Paths_Which_Are_Empty() public void Should_Handle_File_Paths_Which_Are_WhiteSpace() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = " "; @@ -646,6 +858,7 @@ public void Should_Handle_File_Paths_Which_Are_WhiteSpace() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -679,6 +892,7 @@ public void Should_Handle_File_Paths_Which_Are_WhiteSpace() public void Should_Set_File_Path(string filePath, string expectedFilePath) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var line = 10; @@ -697,6 +911,7 @@ public void Should_Set_File_Path(string filePath, string expectedFilePath) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -725,6 +940,7 @@ public sealed class TheLineArgument public void Should_Throw_If_Line_Is_Negative() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -744,6 +960,7 @@ public void Should_Throw_If_Line_Is_Negative() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -768,6 +985,7 @@ public void Should_Throw_If_Line_Is_Negative() public void Should_Throw_If_Line_Is_Zero() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -787,6 +1005,7 @@ public void Should_Throw_If_Line_Is_Zero() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -811,6 +1030,7 @@ public void Should_Throw_If_Line_Is_Zero() public void Should_Throw_If_Line_Is_Set_But_No_File() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; string filePath = null; @@ -830,6 +1050,7 @@ public void Should_Throw_If_Line_Is_Set_But_No_File() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -854,6 +1075,7 @@ public void Should_Throw_If_Line_Is_Set_But_No_File() public void Should_Handle_Line_Which_Is_Null() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -873,6 +1095,7 @@ public void Should_Handle_Line_Which_Is_Null() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -899,6 +1122,7 @@ public void Should_Handle_Line_Which_Is_Null() public void Should_Set_Line(int line) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -917,6 +1141,7 @@ public void Should_Set_Line(int line) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -944,6 +1169,7 @@ public sealed class TheColumnArgument public void Should_Throw_If_Column_Is_Negative() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -963,6 +1189,7 @@ public void Should_Throw_If_Column_Is_Negative() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -987,6 +1214,7 @@ public void Should_Throw_If_Column_Is_Negative() public void Should_Throw_If_Column_Is_Zero() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1006,6 +1234,7 @@ public void Should_Throw_If_Column_Is_Zero() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -1030,6 +1259,7 @@ public void Should_Throw_If_Column_Is_Zero() public void Should_Throw_If_Column_Is_Set_But_No_Line() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1049,6 +1279,7 @@ public void Should_Throw_If_Column_Is_Set_But_No_Line() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -1076,6 +1307,7 @@ public void Should_Throw_If_Column_Is_Set_But_No_Line() public void Should_Set_Column(int? column) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1094,6 +1326,7 @@ public void Should_Set_Column(int? column) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1121,6 +1354,7 @@ public sealed class TheMessageTextArgument public void Should_Throw_If_MessageText_Is_Null() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1140,6 +1374,7 @@ public void Should_Throw_If_MessageText_Is_Null() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -1164,6 +1399,7 @@ public void Should_Throw_If_MessageText_Is_Null() public void Should_Throw_If_MessageText_Is_Empty() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1183,6 +1419,7 @@ public void Should_Throw_If_MessageText_Is_Empty() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -1207,6 +1444,7 @@ public void Should_Throw_If_MessageText_Is_Empty() public void Should_Throw_If_MessageText_Is_WhiteSpace() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1226,6 +1464,7 @@ public void Should_Throw_If_MessageText_Is_WhiteSpace() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -1251,6 +1490,7 @@ public void Should_Throw_If_MessageText_Is_WhiteSpace() public void Should_Set_MessageText(string messageText) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1269,6 +1509,7 @@ public void Should_Set_MessageText(string messageText) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1300,6 +1541,7 @@ public sealed class TheMessageHtmlArgument public void Should_Set_MessageHtml(string messageHtml) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1318,6 +1560,7 @@ public void Should_Set_MessageHtml(string messageHtml) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1349,6 +1592,7 @@ public sealed class TheMessageMarkdownArgument public void Should_Set_MessageHtml(string messageMarkdown) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1367,6 +1611,7 @@ public void Should_Set_MessageHtml(string messageMarkdown) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1400,6 +1645,7 @@ public sealed class ThePriorityArgument public void Should_Set_Priority(int? priority) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1418,6 +1664,7 @@ public void Should_Set_Priority(int? priority) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1445,6 +1692,7 @@ public sealed class ThePriorityNameArgument public void Should_Handle_PriorityNames_Which_Are_Null() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1464,6 +1712,7 @@ public void Should_Handle_PriorityNames_Which_Are_Null() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1488,6 +1737,7 @@ public void Should_Handle_PriorityNames_Which_Are_Null() public void Should_Handle_PriorityNames_Which_Are_Empty() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1507,6 +1757,7 @@ public void Should_Handle_PriorityNames_Which_Are_Empty() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1531,6 +1782,7 @@ public void Should_Handle_PriorityNames_Which_Are_Empty() public void Should_Handle_PriorityNames_Which_Are_WhiteSpace() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1550,6 +1802,7 @@ public void Should_Handle_PriorityNames_Which_Are_WhiteSpace() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1575,6 +1828,7 @@ public void Should_Handle_PriorityNames_Which_Are_WhiteSpace() public void Should_Set_Priority_Name(string priorityName) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1593,6 +1847,7 @@ public void Should_Set_Priority_Name(string priorityName) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1623,6 +1878,7 @@ public sealed class TheRuleArgument public void Should_Set_Rule(string rule) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1641,6 +1897,7 @@ public void Should_Set_Rule(string rule) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1668,6 +1925,7 @@ public sealed class TheRuleUrlArgument public void Should_Set_Rule_Url() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1687,6 +1945,7 @@ public void Should_Set_Rule_Url() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1711,6 +1970,7 @@ public void Should_Set_Rule_Url() public void Should_Set_Rule_Url_If_Null() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1730,6 +1990,7 @@ public void Should_Set_Rule_Url_If_Null() // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1760,6 +2021,7 @@ public sealed class TheRunArgument public void Should_Set_Run(string run) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1778,6 +2040,7 @@ public void Should_Set_Run(string run) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1805,6 +2068,7 @@ public sealed class TheProviderTypeArgument public void Should_Throw_If_Provider_Type_Is_Null() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1824,6 +2088,7 @@ public void Should_Throw_If_Provider_Type_Is_Null() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -1848,6 +2113,7 @@ public void Should_Throw_If_Provider_Type_Is_Null() public void Should_Throw_If_Provider_Type_Is_Empty() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1867,6 +2133,7 @@ public void Should_Throw_If_Provider_Type_Is_Empty() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -1891,6 +2158,7 @@ public void Should_Throw_If_Provider_Type_Is_Empty() public void Should_Throw_If_Provider_Type_Is_WhiteSpace() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1910,6 +2178,7 @@ public void Should_Throw_If_Provider_Type_Is_WhiteSpace() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -1935,6 +2204,7 @@ public void Should_Throw_If_Provider_Type_Is_WhiteSpace() public void Should_Set_ProviderType(string providerType) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1953,6 +2223,7 @@ public void Should_Set_ProviderType(string providerType) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, @@ -1980,6 +2251,7 @@ public sealed class TheProviderNameArgument public void Should_Throw_If_Provider_Name_Is_Null() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -1999,6 +2271,7 @@ public void Should_Throw_If_Provider_Name_Is_Null() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -2023,6 +2296,7 @@ public void Should_Throw_If_Provider_Name_Is_Null() public void Should_Throw_If_Provider_Name_Is_Empty() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -2042,6 +2316,7 @@ public void Should_Throw_If_Provider_Name_Is_Empty() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -2066,6 +2341,7 @@ public void Should_Throw_If_Provider_Name_Is_Empty() public void Should_Throw_If_Provider_Name_Is_WhiteSpace() { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -2085,6 +2361,7 @@ public void Should_Throw_If_Provider_Name_Is_WhiteSpace() // When var result = Record.Exception(() => new Issue( + identifier, projectPath, projectName, filePath, @@ -2110,6 +2387,7 @@ public void Should_Throw_If_Provider_Name_Is_WhiteSpace() public void Should_Set_ProviderName(string providerName) { // Given + var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; @@ -2128,6 +2406,7 @@ public void Should_Set_ProviderName(string providerName) // When var issue = new Issue( + identifier, projectPath, projectName, filePath, diff --git a/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs b/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs index 3acdd342f..15bb98575 100644 --- a/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs +++ b/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs @@ -142,6 +142,7 @@ public void Should_Return_IssueV3() IssueChecker.Check( result, IssueBuilder.NewIssue( + "Identifier", "Something went wrong.", "TestProvider", "Test Provider") @@ -265,6 +266,7 @@ public void Should_Return_List_Of_IssuesV3() IssueChecker.Check( result[0], IssueBuilder.NewIssue( + "Identifier1", "Something went wrong.", "TestProvider", "Test Provider") @@ -277,6 +279,7 @@ public void Should_Return_List_Of_IssuesV3() IssueChecker.Check( result[1], IssueBuilder.NewIssue( + "Identifier2", "Something went wrong again.", "TestProvider", "Test Provider") diff --git a/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs b/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs index 7598cbbf9..e5949382a 100644 --- a/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs +++ b/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs @@ -26,6 +26,23 @@ public void Should_Throw_If_Issue_Is_Null() result.IsArgumentNullException("issue"); } + [Fact] + public void Should_Give_Correct_Result_For_Identifier_After_Roundtrip() + { + // Given + var identifier = "identifier"; + var issue = + IssueBuilder + .NewIssue(identifier, "message", "providerType", "providerName") + .Create(); + + // When + var result = issue.SerializeToJsonString().DeserializeToIssue(); + + // Then + result.Identifier.ShouldBe(identifier); + } + [Fact] public void Should_Give_Correct_Result_For_MessageText_After_Roundtrip() { @@ -309,6 +326,32 @@ public void Should_Throw_If_Issue_Is_Null() result.IsArgumentNullException("issues"); } + [Fact] + public void Should_Give_Correct_Result_For_Identifier_After_Roundtrip() + { + // Given + var identifier1 = "identifier1"; + var identifier2 = "identifier2"; + var issues = + new List + { + IssueBuilder + .NewIssue(identifier1, "messageText1", "providerType1", "providerName1") + .Create(), + IssueBuilder + .NewIssue(identifier2, "messageText2", "providerType2", "providerName2") + .Create(), + }; + + // When + var result = issues.SerializeToJsonString().DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().Identifier.ShouldBe(identifier1); + result.Last().Identifier.ShouldBe(identifier2); + } + [Fact] public void Should_Give_Correct_Result_For_MessageText_After_Roundtrip() { @@ -757,6 +800,35 @@ public void Should_Throw_If_FilePath_Is_Null() result.IsArgumentNullException("filePath"); } + [Fact] + public void Should_Give_Correct_Result_For_Identifier_After_Roundtrip() + { + // Given + var identifier = "identifier"; + var issue = + IssueBuilder + .NewIssue(identifier, "messageText", "providerType", "providerName") + .Create(); + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issue.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssue(); + + // Then + result.Identifier.ShouldBe(identifier); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_MessageText_After_Roundtrip() { @@ -1235,6 +1307,44 @@ public void Should_Throw_If_FilePath_Is_Null() result.IsArgumentNullException("filePath"); } + [Fact] + public void Should_Give_Correct_Result_For_Identifier_After_Roundtrip() + { + // Given + var identifier1 = "identifier1"; + var identifier2 = "identifier2"; + var issues = + new List + { + IssueBuilder + .NewIssue(identifier1, "messageText1", "providerType1", "providerName1") + .Create(), + IssueBuilder + .NewIssue(identifier2, "messageText2", "providerType2", "providerName2") + .Create(), + }; + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issues.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().Identifier.ShouldBe(identifier1); + result.Last().Identifier.ShouldBe(identifier2); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_MessageText_After_Roundtrip() { diff --git a/src/Cake.Issues.Tests/Testfiles/issueV3.json b/src/Cake.Issues.Tests/Testfiles/issueV3.json index 731a61ce5..0c4d07046 100644 --- a/src/Cake.Issues.Tests/Testfiles/issueV3.json +++ b/src/Cake.Issues.Tests/Testfiles/issueV3.json @@ -1,5 +1,6 @@ { "Version": 3, + "Identifier": "Identifier", "AffectedFileRelativePath": "src\/Foo\/Bar.cs", "Line": 42, "Column": 23, diff --git a/src/Cake.Issues.Tests/Testfiles/issuesV3.json b/src/Cake.Issues.Tests/Testfiles/issuesV3.json index 89985df73..1c79f4ae4 100644 --- a/src/Cake.Issues.Tests/Testfiles/issuesV3.json +++ b/src/Cake.Issues.Tests/Testfiles/issuesV3.json @@ -1,6 +1,7 @@ [ { "Version": 3, + "Identifier": "Identifier1", "AffectedFileRelativePath": "src\/Foo\/Bar.cs", "Line": 42, "Column": 23, @@ -18,6 +19,7 @@ }, { "Version": 3, + "Identifier": "Identifier2", "AffectedFileRelativePath": "src\/Foo\/Bar2.cs", "Line": null, "Column": null, diff --git a/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs b/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs index 81af41b19..57b9b3bd5 100644 --- a/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs +++ b/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs @@ -5,16 +5,17 @@ internal class IssueCheckerFixture : IssueBuilderFixture { public IssueCheckerFixture() - : this("Message", "ProviderType", "ProviderName") + : this("Identifier", "Message", "ProviderType", "ProviderName") { } - public IssueCheckerFixture(string messageText, string providerType, string providerName) - : base(messageText, providerType, providerName) + public IssueCheckerFixture(string identifier, string messageText, string providerType, string providerName) + : base(identifier, messageText, providerType, providerName) { this.ProviderType = providerType; this.ProviderName = providerName; this.Run = "Test Run"; + this.Identifier = identifier; this.ProjectFileRelativePath = @"src\project.file"; this.ProjectName = "ProjectName"; this.AffectedFileRelativePath = @"src\source.file"; @@ -49,6 +50,8 @@ public IssueCheckerFixture(string messageText, string providerType, string provi public string Run { get; private set; } + public string Identifier { get; private set; } + public string ProjectFileRelativePath { get; private set; } public string ProjectName { get; private set; } diff --git a/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs b/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs index 1d2292465..ba8f252f3 100644 --- a/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs +++ b/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs @@ -145,6 +145,7 @@ public void Should_Throw_If_Issue_Is_Null() fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -174,6 +175,7 @@ public void Should_Not_Throw_If_All_Values_Are_The_Same() fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -198,7 +200,7 @@ public void Should_Not_Throw_If_All_Values_Are_The_Same() public void Should_Throw_If_ProviderType_Is_Different(string expectedValue, string actualValue) { // Given - var fixture = new IssueCheckerFixture("Message", actualValue, "ProviderName"); + var fixture = new IssueCheckerFixture("Identifier", "Message", actualValue, "ProviderName"); // When var result = Record.Exception(() => @@ -207,6 +209,7 @@ public void Should_Throw_If_ProviderType_Is_Different(string expectedValue, stri expectedValue, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -233,7 +236,7 @@ public void Should_Throw_If_ProviderType_Is_Different(string expectedValue, stri public void Should_Throw_If_ProviderName_Is_Different(string expectedValue, string actualValue) { // Given - var fixture = new IssueCheckerFixture("Message", "ProviderType", actualValue); + var fixture = new IssueCheckerFixture("Identifier", "Message", "ProviderType", actualValue); // When var result = Record.Exception(() => @@ -242,6 +245,7 @@ public void Should_Throw_If_ProviderName_Is_Different(string expectedValue, stri fixture.ProviderType, expectedValue, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -281,6 +285,7 @@ public void Should_Throw_If_Run_Is_Different(string expectedValue, string actual fixture.ProviderType, fixture.ProviderName, expectedValue, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -299,6 +304,42 @@ public void Should_Throw_If_Run_Is_Different(string expectedValue, string actual result.Message.ShouldStartWith("Expected issue.Run"); } + [Theory] + [InlineData("Message", "Foo")] + [InlineData(null, "Foo")] + [InlineData("", "Foo")] + [InlineData(" ", "Foo")] + public void Should_Throw_If_Identifier_Is_Different(string expectedValue, string actualValue) + { + // Given + var fixture = new IssueCheckerFixture(actualValue, "Message", "ProviderType", "ProviderName"); + + // When + var result = Record.Exception(() => + IssueChecker.Check( + fixture.Issue, + fixture.ProviderType, + fixture.ProviderName, + fixture.Run, + expectedValue, + fixture.ProjectFileRelativePath, + fixture.ProjectName, + fixture.AffectedFileRelativePath, + fixture.Line, + fixture.Column, + fixture.MessageText, + fixture.MessageHtml, + fixture.MessageMarkdown, + fixture.Priority, + fixture.PriorityName, + fixture.Rule, + fixture.RuleUrl)); + + // Then + result.ShouldBeOfType(); + result.Message.ShouldStartWith("Expected issue.Identifier"); + } + [Theory] [InlineData(@"src\project.file", @"src\foo")] public void Should_Throw_If_ProjectFileRelativePath_Is_Different(string expectedValue, string actualValue) @@ -317,6 +358,7 @@ public void Should_Throw_If_ProjectFileRelativePath_Is_Different(string expected fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, expectedValue, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -356,6 +398,7 @@ public void Should_Throw_If_ProjectName_Is_Different(string expectedValue, strin fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, expectedValue, fixture.AffectedFileRelativePath, @@ -392,6 +435,7 @@ public void Should_Throw_If_AffectedFileRelativePath_Is_Different(string expecte fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, expectedValue, @@ -430,6 +474,7 @@ public void Should_Throw_If_Line_Is_Different(int? expectedValue, int? actualVal fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -468,6 +513,7 @@ public void Should_Throw_If_Column_Is_Different(int? expectedValue, int? actualV fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -494,7 +540,7 @@ public void Should_Throw_If_Column_Is_Different(int? expectedValue, int? actualV public void Should_Throw_If_MessageText_Is_Different(string expectedValue, string actualValue) { // Given - var fixture = new IssueCheckerFixture(actualValue, "ProviderType", "ProviderName"); + var fixture = new IssueCheckerFixture("Identifier", actualValue, "ProviderType", "ProviderName"); // When var result = Record.Exception(() => @@ -503,6 +549,7 @@ public void Should_Throw_If_MessageText_Is_Different(string expectedValue, strin fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -542,6 +589,7 @@ public void Should_Throw_If_MessageHtml_Is_Different(string expectedValue, strin fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -581,6 +629,7 @@ public void Should_Throw_If_MessageMarkdown_Is_Different(string expectedValue, s fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -617,6 +666,7 @@ public void Should_Throw_If_Priority_Is_Different(IssuePriority expectedValue, I fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -656,6 +706,7 @@ public void Should_Throw_If_PriorityName_Is_Different(string expectedValue, stri fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -695,6 +746,7 @@ public void Should_Throw_If_Rule_Is_Different(string expectedValue, string actua fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, @@ -731,6 +783,7 @@ public void Should_Throw_If_RuleUrl_Is_Different(string expectedValue, string ac fixture.ProviderType, fixture.ProviderName, fixture.Run, + fixture.Identifier, fixture.ProjectFileRelativePath, fixture.ProjectName, fixture.AffectedFileRelativePath, diff --git a/src/Cake.Issues/Aliases.NewIssue.cs b/src/Cake.Issues/Aliases.NewIssue.cs index a97ee1172..3e23ad827 100644 --- a/src/Cake.Issues/Aliases.NewIssue.cs +++ b/src/Cake.Issues/Aliases.NewIssue.cs @@ -9,7 +9,7 @@ public static partial class Aliases { /// - /// Initiates the creation of a new . + /// Initiates the creation of a new with as identifier. /// /// The context. /// The message of the issue. @@ -46,5 +46,54 @@ public static IssueBuilder NewIssue( return IssueBuilder.NewIssue(message, providerType, providerName); } + + /// + /// Initiates the creation of a new . + /// + /// The context. + /// The identifier of the issue. + /// The message of the issue. + /// The unique identifier of the issue provider. + /// The human friendly name of the issue provider. + /// Builder class for creating a new . + /// + /// Create a new warning for the myfile.txt file on line 42: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.CreateCakeAliasCategory)] + public static IssueBuilder NewIssue( + this ICakeContext context, + string identifier, + string message, + string providerType, + string providerName) + { +#pragma warning disable SA1123 // Do not place regions within elements + #region DupFinder Exclusion +#pragma warning restore SA1123 // Do not place regions within elements + + context.NotNull(nameof(context)); + identifier.NotNullOrWhiteSpace(nameof(identifier)); + message.NotNullOrWhiteSpace(nameof(message)); + providerType.NotNullOrWhiteSpace(nameof(providerType)); + providerName.NotNullOrWhiteSpace(nameof(providerName)); + + #endregion + + return IssueBuilder.NewIssue(identifier, message, providerType, providerName); + } } } diff --git a/src/Cake.Issues/IIssue.cs b/src/Cake.Issues/IIssue.cs index 2a5171301..63754d95e 100644 --- a/src/Cake.Issues/IIssue.cs +++ b/src/Cake.Issues/IIssue.cs @@ -8,6 +8,12 @@ /// public interface IIssue { + /// + /// Gets the identifier for the message. + /// The identifier can be used to identify the same issue across multiple runs. + /// + string Identifier { get; } + /// /// Gets the path to the project to which the file affected by the issue belongs. /// The path is relative to the repository root. diff --git a/src/Cake.Issues/IIssueComparer.cs b/src/Cake.Issues/IIssueComparer.cs index 7c5fb4a94..cb2996cd6 100644 --- a/src/Cake.Issues/IIssueComparer.cs +++ b/src/Cake.Issues/IIssueComparer.cs @@ -62,6 +62,7 @@ public bool Equals(IIssue x, IIssue y) } return + (x.Identifier == y.Identifier) && (this.compareOnlyPersistentProperties || x.ProjectFileRelativePath?.FullPath == y.ProjectFileRelativePath?.FullPath) && (x.ProjectName == y.ProjectName) && (this.compareOnlyPersistentProperties || x.AffectedFileRelativePath?.FullPath == y.AffectedFileRelativePath?.FullPath) && @@ -91,6 +92,7 @@ public int GetHashCode(IIssue obj) { return GetHashCode( + obj.Identifier, obj.ProjectName, obj.MessageText, obj.MessageHtml, @@ -107,6 +109,7 @@ public int GetHashCode(IIssue obj) { return GetHashCode( + obj.Identifier, obj.ProjectFileRelativePath?.ToString(), obj.ProjectName, obj.AffectedFileRelativePath?.ToString(), diff --git a/src/Cake.Issues/IIssueExtensions.cs b/src/Cake.Issues/IIssueExtensions.cs index a9686ae87..47bb10441 100644 --- a/src/Cake.Issues/IIssueExtensions.cs +++ b/src/Cake.Issues/IIssueExtensions.cs @@ -108,6 +108,10 @@ public static string FileName(this IIssue issue) /// The value of . /// /// + /// {Identifier} + /// The value of . + /// + /// /// {Priority} /// The value of . /// @@ -186,6 +190,7 @@ public static string ReplaceIssuePattern(this string pattern, IIssue issue) pattern .Replace("{ProviderType}", issue.ProviderType) .Replace("{ProviderName}", issue.ProviderName) + .Replace("{Identifier}", issue.Identifier) .Replace("{Priority}", issue.Priority?.ToString()) .Replace("{PriorityName}", issue.PriorityName) .Replace("{ProjectPath}", issue.ProjectPath()) diff --git a/src/Cake.Issues/Issue.cs b/src/Cake.Issues/Issue.cs index 45acc820b..0ce30d074 100644 --- a/src/Cake.Issues/Issue.cs +++ b/src/Cake.Issues/Issue.cs @@ -11,6 +11,8 @@ public class Issue : IIssue /// /// Initializes a new instance of the class. /// + /// The identifier of the issue. + /// The identifier needs to be identical across multiple runs of an issue provider for the same issue. /// The path to the project to which the file affected by the issue belongs. /// The path needs to be relative to the repository root. /// Can be null or if issue is not related to a project. @@ -38,6 +40,7 @@ public class Issue : IIssue /// The type of the issue provider. /// The human friendly name of the issue provider. public Issue( + string identifier, string projectFileRelativePath, string projectName, string affectedFileRelativePath, @@ -54,6 +57,7 @@ public Issue( string providerType, string providerName) { + identifier.NotNullOrWhiteSpace(nameof(identifier)); line?.NotNegativeOrZero(nameof(line)); column?.NotNegativeOrZero(nameof(column)); messageText.NotNullOrWhiteSpace(nameof(messageText)); @@ -106,6 +110,7 @@ public Issue( throw new ArgumentOutOfRangeException(nameof(column), $"Cannot specify a column while not specifying a line."); } + this.Identifier = identifier; this.ProjectName = projectName; this.Line = line; this.Column = column; @@ -121,6 +126,9 @@ public Issue( this.ProviderName = providerName; } + /// + public string Identifier { get; } + /// public FilePath ProjectFileRelativePath { get; } diff --git a/src/Cake.Issues/IssueBuilder.cs b/src/Cake.Issues/IssueBuilder.cs index b7582f5f9..90ff204f9 100644 --- a/src/Cake.Issues/IssueBuilder.cs +++ b/src/Cake.Issues/IssueBuilder.cs @@ -7,6 +7,7 @@ /// public class IssueBuilder { + private readonly string identifier; private readonly string providerType; private readonly string providerName; private readonly string messageText; @@ -26,50 +27,66 @@ public class IssueBuilder /// /// Initializes a new instance of the class. /// + /// The identifier of the message. /// The message of the issue in plain text format. /// The type of the issue provider. /// The human friendly name of the issue provider. private IssueBuilder( + string identifier, string message, string providerType, string providerName) { +#pragma warning disable SA1123 // Do not place regions within elements + #region DupFinder Exclusion +#pragma warning restore SA1123 // Do not place regions within elements + + identifier.NotNullOrWhiteSpace(nameof(identifier)); message.NotNullOrWhiteSpace(nameof(message)); providerType.NotNullOrWhiteSpace(nameof(providerType)); providerName.NotNullOrWhiteSpace(nameof(providerName)); + #endregion + + this.identifier = identifier; this.messageText = message; this.providerType = providerType; this.providerName = providerName; } /// - /// Initiates the creation of a new . + /// Initiates the creation of a new with + /// as identifier. /// + /// Type of the issue provider which has the issue created. /// The message of the issue in plain text format. - /// The type of the issue provider. - /// The human friendly name of the issue provider. + /// Issue provider which has the issue created. /// Builder class for creating a new issue. - public static IssueBuilder NewIssue( + public static IssueBuilder NewIssue( string message, - string providerType, - string providerName) + T issueProvider) + where T : IIssueProvider { + if (issueProvider == null) + { + throw new ArgumentNullException(nameof(issueProvider)); + } + message.NotNullOrWhiteSpace(nameof(message)); - providerType.NotNullOrWhiteSpace(nameof(providerType)); - providerName.NotNullOrWhiteSpace(nameof(providerName)); - return new IssueBuilder(message, providerType, providerName); + return NewIssue(message, message, issueProvider); } /// /// Initiates the creation of a new . /// /// Type of the issue provider which has the issue created. + /// The identifier of the message. /// The message of the issue in plain text format. /// Issue provider which has the issue created. /// Builder class for creating a new issue. public static IssueBuilder NewIssue( + string identifier, string message, T issueProvider) where T : IIssueProvider @@ -81,7 +98,54 @@ public static IssueBuilder NewIssue( message.NotNullOrWhiteSpace(nameof(message)); - return new IssueBuilder(message, typeof(T).FullName, issueProvider.ProviderName); + return NewIssue(identifier, message, typeof(T).FullName, issueProvider.ProviderName); + } + + /// + /// Initiates the creation of a new with as identifier. + /// + /// The message of the issue in plain text format. + /// The type of the issue provider. + /// The human friendly name of the issue provider. + /// Builder class for creating a new issue. + public static IssueBuilder NewIssue( + string message, + string providerType, + string providerName) + { + message.NotNullOrWhiteSpace(nameof(message)); + providerType.NotNullOrWhiteSpace(nameof(providerType)); + providerName.NotNullOrWhiteSpace(nameof(providerName)); + + return NewIssue(message, message, providerType, providerName); + } + + /// + /// Initiates the creation of a new . + /// + /// The identifier of the message. + /// The message of the issue in plain text format. + /// The type of the issue provider. + /// The human friendly name of the issue provider. + /// Builder class for creating a new issue. + public static IssueBuilder NewIssue( + string identifier, + string message, + string providerType, + string providerName) + { +#pragma warning disable SA1123 // Do not place regions within elements + #region DupFinder Exclusion +#pragma warning restore SA1123 // Do not place regions within elements + + identifier.NotNullOrWhiteSpace(nameof(identifier)); + message.NotNullOrWhiteSpace(nameof(message)); + providerType.NotNullOrWhiteSpace(nameof(providerType)); + providerName.NotNullOrWhiteSpace(nameof(providerName)); + + #endregion + + return new IssueBuilder(identifier, message, providerType, providerName); } /// @@ -287,6 +351,7 @@ public IIssue Create() { return new Issue( + this.identifier, this.projectFileRelativePath, this.projectName, this.filePath, diff --git a/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs b/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs index f56c42eb7..2945a5f08 100644 --- a/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs +++ b/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs @@ -80,6 +80,7 @@ internal static SerializableIssueV3 ToSerializableIssue(this IIssue issue) return new SerializableIssueV3 { + Identifier = issue.Identifier, ProjectFileRelativePath = issue.ProjectFileRelativePath?.FullPath, ProjectName = issue.ProjectName, AffectedFileRelativePath = issue.AffectedFileRelativePath?.FullPath, diff --git a/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs b/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs index 17043daa5..c4ab1ba43 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs @@ -27,6 +27,7 @@ internal static Issue ToIssue(this SerializableIssue serializableIssue) } return new Issue( + serializableIssue.Message, serializableIssue.ProjectFileRelativePath, serializableIssue.ProjectName, serializableIssue.AffectedFileRelativePath, diff --git a/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs b/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs index d1f9dc397..8e57b6c3a 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs @@ -27,6 +27,7 @@ internal static Issue ToIssue(this SerializableIssueV2 serializableIssue) } return new Issue( + serializableIssue.MessageText, serializableIssue.ProjectFileRelativePath, serializableIssue.ProjectName, serializableIssue.AffectedFileRelativePath, diff --git a/src/Cake.Issues/Serialization/SerializableIssueV3.cs b/src/Cake.Issues/Serialization/SerializableIssueV3.cs index 749dc7cdc..7bc31b02d 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV3.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV3.cs @@ -20,6 +20,10 @@ public int Version } } + /// + [DataMember] + public string Identifier { get; set; } + /// [DataMember] public string ProjectFileRelativePath { get; set; } diff --git a/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs b/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs index ffa3f222f..a1f3c1ebe 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs @@ -27,6 +27,7 @@ internal static Issue ToIssue(this SerializableIssueV3 serializableIssue) } return new Issue( + serializableIssue.Identifier, serializableIssue.ProjectFileRelativePath, serializableIssue.ProjectName, serializableIssue.AffectedFileRelativePath, From ea471532ff68e629f74f8fe522e53898bb3be860 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Sat, 4 Jul 2020 12:30:01 +0200 Subject: [PATCH 14/31] (GH-168) Add possibility to define range of line / column --- src/Cake.Issues.Testing/IssueChecker.cs | 20 + .../IIssueExtensionsTests.cs | 4 +- src/Cake.Issues.Tests/IssueBuilderTests.cs | 263 +++++ src/Cake.Issues.Tests/IssueTests.cs | 998 +++++++++++++++++- .../IssueDeserializationExtensionsTests.cs | 4 +- .../IssueSerializationExtensionsTests.cs | 232 ++++ src/Cake.Issues.Tests/Testfiles/issueV3.json | 6 +- src/Cake.Issues.Tests/Testfiles/issuesV3.json | 4 + .../Testing/IssueCheckerFixture.cs | 8 +- .../Testing/IssueCheckerTests.cs | 122 ++- src/Cake.Issues/IIssue.cs | 12 + src/Cake.Issues/IIssueComparer.cs | 10 + src/Cake.Issues/IIssueExtensions.cs | 10 + src/Cake.Issues/Issue.cs | 38 +- src/Cake.Issues/IssueBuilder.cs | 40 +- .../IssueSerializationExtensions.cs | 2 + .../SerializableIssueExtensions.cs | 2 + .../SerializableIssueV2Extensions.cs | 2 + .../Serialization/SerializableIssueV3.cs | 8 + .../SerializableIssueV3Extensions.cs | 2 + 20 files changed, 1751 insertions(+), 36 deletions(-) diff --git a/src/Cake.Issues.Testing/IssueChecker.cs b/src/Cake.Issues.Testing/IssueChecker.cs index 2d42e8d64..9f5007d93 100644 --- a/src/Cake.Issues.Testing/IssueChecker.cs +++ b/src/Cake.Issues.Testing/IssueChecker.cs @@ -47,7 +47,9 @@ public static void Check( expectedIssue.ProjectName, expectedIssue.AffectedFileRelativePath?.ToString(), expectedIssue.Line, + expectedIssue.EndLine, expectedIssue.Column, + expectedIssue.EndColumn, expectedIssue.MessageText, expectedIssue.MessageHtml, expectedIssue.MessageMarkdown, @@ -73,8 +75,12 @@ public static void Check( /// null if the issue is not expected to be related to a change in a file. /// Expected line number. /// null if the issue is not expected to be related to a file or specific line. + /// Expected end of line range. + /// null if the issue is not expected to be related to a file, specific line or range of lines. /// Expected column. /// null if the issue is not expected to be related to a file or specific column. + /// Expected end of column range. + /// null if the issue is not expected to be related to a file, specific column or range of columns. /// Expected message in plain text format. /// Expected message in HTML format. /// Expected message in Markdown format. @@ -96,7 +102,9 @@ public static void Check( string projectName, string affectedFileRelativePath, int? line, + int? endLine, int? column, + int? endColumn, string messageText, string messageHtml, string messageMarkdown, @@ -189,12 +197,24 @@ public static void Check( $"Expected issue.Line to be '{line}' but was '{issue.Line}'."); } + if (issue.EndLine != endLine) + { + throw new Exception( + $"Expected issue.EndLine to be '{endLine}' but was '{issue.EndLine}'."); + } + if (issue.Column != column) { throw new Exception( $"Expected issue.Column to be '{column}' but was '{issue.Column}'."); } + if (issue.EndColumn != endColumn) + { + throw new Exception( + $"Expected issue.EndColumn to be '{endColumn}' but was '{issue.EndColumn}'."); + } + if (issue.MessageText != messageText) { throw new Exception( diff --git a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs index dc2bc48c9..fc1193e48 100644 --- a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs +++ b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs @@ -308,7 +308,9 @@ public void Should_Throw_If_Issue_Is_Null() [InlineData("foo {FileDirectory} bar", "foo src/Cake.Issues bar")] [InlineData("foo {FileName} bar", "foo foo.cs bar")] [InlineData("foo {Line} bar", "foo 42 bar")] + [InlineData("foo {EndLine} bar", "foo 420 bar")] [InlineData("foo {Column} bar", "foo 23 bar")] + [InlineData("foo {EndColumn} bar", "foo 230 bar")] [InlineData("foo {Rule} bar", "foo Rule Foo bar")] [InlineData("foo {RuleUrl} bar", "foo https://google.com/ bar")] [InlineData("foo {MessageText} bar", "foo MessageText Foo bar")] @@ -323,7 +325,7 @@ public void Should_Replace_Tokens(string pattern, string expectedResult) .ForRun("Run") .WithMessageInHtmlFormat("MessageHtml Foo") .WithMessageInMarkdownFormat("MessageMarkdown Foo") - .InFile(@"src/Cake.Issues/foo.cs", 42, 23) + .InFile(@"src/Cake.Issues/foo.cs", 42, 420, 23, 230) .InProject(@"src/Cake.Issues/Cake.Issues.csproj", "Cake.Issues") .OfRule("Rule Foo", new Uri("https://google.com")) .WithPriority(IssuePriority.Error) diff --git a/src/Cake.Issues.Tests/IssueBuilderTests.cs b/src/Cake.Issues.Tests/IssueBuilderTests.cs index c12f6e5e5..d5d36a99d 100644 --- a/src/Cake.Issues.Tests/IssueBuilderTests.cs +++ b/src/Cake.Issues.Tests/IssueBuilderTests.cs @@ -1274,6 +1274,19 @@ public void Should_Throw_If_Column_Is_Zero() result.IsArgumentOutOfRangeException("column"); } + [Fact] + public void Should_Handle_Line_Which_Is_Null() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", null, null).Create(); + + // Then + issue.Line.ShouldBe(null); + } + [Fact] public void Should_Handle_Column_Which_Is_Null() { @@ -1341,6 +1354,256 @@ public void Should_Set_Column(int column) } } + public sealed class TheInFileLineRangeColumnRangeMethod + { + [Fact] + public void Should_Throw_If_StartLine_Is_Negative() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", -1, 50, 1, 10)); + + // Then + result.IsArgumentOutOfRangeException("startLine"); + } + + [Fact] + public void Should_Throw_If_StartLine_Is_Zero() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", 0, 50, 1, 10)); + + // Then + result.IsArgumentOutOfRangeException("startLine"); + } + + [Fact] + public void Should_Throw_If_EndLine_Is_Negative() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", 5, -1, 1, 10)); + + // Then + result.IsArgumentOutOfRangeException("endLine"); + } + + [Fact] + public void Should_Throw_If_EndLine_Is_Zero() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", 5, 0, 1, 10)); + + // Then + result.IsArgumentOutOfRangeException("endLine"); + } + + [Fact] + public void Should_Throw_If_StartColumn_Is_Negative() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", 5, 50, -1, 10)); + + // Then + result.IsArgumentOutOfRangeException("startColumn"); + } + + [Fact] + public void Should_Throw_If_StartColumn_Is_Zero() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", 5, 50, 0, 10)); + + // Then + result.IsArgumentOutOfRangeException("startColumn"); + } + + [Fact] + public void Should_Throw_If_EndColumn_Is_Negative() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", 5, 50, 1, -1)); + + // Then + result.IsArgumentOutOfRangeException("endColumn"); + } + + [Fact] + public void Should_Throw_If_EndColumn_Is_Zero() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.InFile("foo", 5, 50, 1, 0)); + + // Then + result.IsArgumentOutOfRangeException("endColumn"); + } + + [Fact] + public void Should_Handle_StartLine_Which_Is_Null() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", null, null, null, null).Create(); + + // Then + issue.Line.ShouldBe(null); + } + + [Fact] + public void Should_Handle_EndLine_Which_Is_Null() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", 5, null, null, null).Create(); + + // Then + issue.EndLine.ShouldBe(null); + } + + [Fact] + public void Should_Handle_StartColumn_Which_Is_Null() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", 5, 50, null, null).Create(); + + // Then + issue.Column.ShouldBe(null); + } + + [Fact] + public void Should_Handle_EndColumn_Which_Is_Null() + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", 5, 50, 1, null).Create(); + + // Then + issue.EndColumn.ShouldBe(null); + } + + [Theory] + [InlineData(@"foo", @"foo")] + [InlineData(@"foo\bar", @"foo/bar")] + [InlineData(@"foo/bar", @"foo/bar")] + [InlineData(@"foo\bar\", @"foo/bar")] + [InlineData(@"foo/bar/", @"foo/bar")] + [InlineData(@".\foo", @"foo")] + [InlineData(@"./foo", @"foo")] + [InlineData(@"foo\..\bar", @"foo/../bar")] + [InlineData(@"foo/../bar", @"foo/../bar")] + public void Should_Set_FilePath(string filePath, string expectedFilePath) + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile(filePath, 5, 50, 1, 10).Create(); + + // Then + issue.AffectedFileRelativePath.ToString().ShouldBe(expectedFilePath); + issue.AffectedFileRelativePath.IsRelative.ShouldBe(true, "File path was not set as relative."); + } + + [Theory] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void Should_Set_StartLine(int startLine) + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", startLine, null, 1, 10).Create(); + + // Then + issue.Line.ShouldBe(startLine); + } + + [Theory] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void Should_Set_EndLine(int endLine) + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", 1, endLine, 1, 10).Create(); + + // Then + issue.EndLine.ShouldBe(endLine); + } + + [Theory] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void Should_Set_StartColumn(int startColumn) + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", 5, 50, startColumn, null).Create(); + + // Then + issue.Column.ShouldBe(startColumn); + } + + [Theory] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void Should_Set_EndColumn(int endColumn) + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.InFile("foo", 5, 50, 1, endColumn).Create(); + + // Then + issue.EndColumn.ShouldBe(endColumn); + } + } + public sealed class TheWithPriorityMethod { [Fact] diff --git a/src/Cake.Issues.Tests/IssueTests.cs b/src/Cake.Issues.Tests/IssueTests.cs index bad01c7ad..ee166c372 100644 --- a/src/Cake.Issues.Tests/IssueTests.cs +++ b/src/Cake.Issues.Tests/IssueTests.cs @@ -20,7 +20,9 @@ public void Should_Throw_If_Identifier_Is_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -40,7 +42,9 @@ public void Should_Throw_If_Identifier_Is_Null() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -65,7 +69,9 @@ public void Should_Throw_If_Identifier_Is_Empty() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -85,7 +91,9 @@ public void Should_Throw_If_Identifier_Is_Empty() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -110,7 +118,9 @@ public void Should_Throw_If_Identifier_Is_WhiteSpace() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -130,7 +140,9 @@ public void Should_Throw_If_Identifier_Is_WhiteSpace() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -155,7 +167,9 @@ public void Should_Set_Identifier(string identifier) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -175,7 +189,9 @@ public void Should_Set_Identifier(string identifier) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -202,8 +218,10 @@ public void Should_Throw_If_Project_Path_Is_Invalid(string projectPath) var identifier = "identifier"; var projectName = "foo"; var filePath = @"src\foo.cs"; - var line = 100; + var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -223,7 +241,9 @@ public void Should_Throw_If_Project_Path_Is_Invalid(string projectPath) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -249,8 +269,10 @@ public void Should_Throw_If_File_Path_Is_Absolute(string projectPath) var identifier = "identifier"; var projectName = "foo"; var filePath = @"src\foo.cs"; - var line = 100; + var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -270,7 +292,9 @@ public void Should_Throw_If_File_Path_Is_Absolute(string projectPath) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -295,7 +319,9 @@ public void Should_Handle_Project_Paths_Which_Are_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -315,7 +341,9 @@ public void Should_Handle_Project_Paths_Which_Are_Null() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -340,7 +368,9 @@ public void Should_Handle_Project_Paths_Which_Are_Empty() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -360,7 +390,9 @@ public void Should_Handle_Project_Paths_Which_Are_Empty() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -385,7 +417,9 @@ public void Should_Handle_Project_Paths_Which_Are_WhiteSpace() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -405,7 +439,9 @@ public void Should_Handle_Project_Paths_Which_Are_WhiteSpace() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -430,7 +466,9 @@ public void Should_Set_ProjectFileRelativePath(string projectPath) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -450,7 +488,9 @@ public void Should_Set_ProjectFileRelativePath(string projectPath) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -478,7 +518,9 @@ public void Should_Handle_Projects_Which_Are_Null() string projectName = null; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -498,7 +540,9 @@ public void Should_Handle_Projects_Which_Are_Null() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -523,7 +567,9 @@ public void Should_Handle_Projects_Which_Are_Empty() var projectName = string.Empty; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -543,7 +589,9 @@ public void Should_Handle_Projects_Which_Are_Empty() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -568,7 +616,9 @@ public void Should_Handle_Projects_Which_Are_WhiteSpace() var projectName = " "; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -588,7 +638,9 @@ public void Should_Handle_Projects_Which_Are_WhiteSpace() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -613,7 +665,9 @@ public void Should_Set_ProjectName(string projectName) var projectPath = @"src\foo.csproj"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -633,7 +687,9 @@ public void Should_Set_ProjectName(string projectName) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -660,8 +716,10 @@ public void Should_Throw_If_File_Path_Is_Invalid(string filePath) var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; - var line = 100; + var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -681,7 +739,9 @@ public void Should_Throw_If_File_Path_Is_Invalid(string filePath) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -707,8 +767,10 @@ public void Should_Throw_If_File_Path_Is_Absolute(string filePath) var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; - var line = 100; + var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -728,7 +790,9 @@ public void Should_Throw_If_File_Path_Is_Absolute(string filePath) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -753,7 +817,9 @@ public void Should_Handle_File_Paths_Which_Are_Null() var projectName = "foo"; string filePath = null; int? line = null; + int? endLine = null; int? column = null; + int? endColumn = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -773,7 +839,9 @@ public void Should_Handle_File_Paths_Which_Are_Null() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -798,7 +866,9 @@ public void Should_Handle_File_Paths_Which_Are_Empty() var projectName = "foo"; var filePath = string.Empty; int? line = null; + int? endLine = null; int? column = null; + int? endColumn = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -818,7 +888,9 @@ public void Should_Handle_File_Paths_Which_Are_Empty() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -843,7 +915,9 @@ public void Should_Handle_File_Paths_Which_Are_WhiteSpace() var projectName = "foo"; var filePath = " "; int? line = null; + int? endLine = null; int? column = null; + int? endColumn = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -863,7 +937,9 @@ public void Should_Handle_File_Paths_Which_Are_WhiteSpace() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -896,7 +972,9 @@ public void Should_Set_File_Path(string filePath, string expectedFilePath) var projectPath = @"src\foo.csproj"; var projectName = "foo"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -916,7 +994,9 @@ public void Should_Set_File_Path(string filePath, string expectedFilePath) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -945,7 +1025,9 @@ public void Should_Throw_If_Line_Is_Negative() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = -1; - var column = 50; + int? endLine = null; + int? column = null; + int? endColumn = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -965,7 +1047,9 @@ public void Should_Throw_If_Line_Is_Negative() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -990,7 +1074,9 @@ public void Should_Throw_If_Line_Is_Zero() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 0; - var column = 50; + int? endLine = null; + int? column = null; + int? endColumn = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1010,7 +1096,9 @@ public void Should_Throw_If_Line_Is_Zero() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1035,7 +1123,9 @@ public void Should_Throw_If_Line_Is_Set_But_No_File() var projectName = "foo"; string filePath = null; var line = 10; - var column = 50; + int? endLine = null; + int? column = null; + int? endColumn = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1055,7 +1145,9 @@ public void Should_Throw_If_Line_Is_Set_But_No_File() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1080,7 +1172,9 @@ public void Should_Handle_Line_Which_Is_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; int? line = null; + int? endLine = null; int? column = null; + int? endColumn = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1100,7 +1194,9 @@ public void Should_Handle_Line_Which_Is_Null() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1126,7 +1222,9 @@ public void Should_Set_Line(int line) var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; + int? endLine = null; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1146,7 +1244,9 @@ public void Should_Set_Line(int line) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1163,18 +1263,20 @@ public void Should_Set_Line(int line) } } - public sealed class TheColumnArgument + public sealed class TheEndLineArgument { [Fact] - public void Should_Throw_If_Column_Is_Negative() + public void Should_Throw_If_EndLine_Is_Negative() { // Given var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; - var line = 100; - var column = -1; + var line = 10; + var endLine = -1; + int? column = null; + int? endColumn = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1194,7 +1296,9 @@ public void Should_Throw_If_Column_Is_Negative() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1207,19 +1311,21 @@ public void Should_Throw_If_Column_Is_Negative() providerName)); // Then - result.IsArgumentOutOfRangeException("column"); + result.IsArgumentOutOfRangeException("endLine"); } [Fact] - public void Should_Throw_If_Column_Is_Zero() + public void Should_Throw_If_EndLine_Is_Zero() { // Given var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; - var line = 100; - var column = 0; + var line = 10; + var endLine = 0; + int? column = null; + int? endColumn = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1239,7 +1345,9 @@ public void Should_Throw_If_Column_Is_Zero() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1252,11 +1360,11 @@ public void Should_Throw_If_Column_Is_Zero() providerName)); // Then - result.IsArgumentOutOfRangeException("column"); + result.IsArgumentOutOfRangeException("endLine"); } [Fact] - public void Should_Throw_If_Column_Is_Set_But_No_Line() + public void Should_Throw_If_EndLine_Is_Set_But_No_Line() { // Given var identifier = "identifier"; @@ -1264,7 +1372,9 @@ public void Should_Throw_If_Column_Is_Set_But_No_Line() var projectName = "foo"; var filePath = @"src\foo.cs"; int? line = null; - var column = 50; + var endLine = 12; + int? column = null; + int? endColumn = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1284,7 +1394,9 @@ public void Should_Throw_If_Column_Is_Set_But_No_Line() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1297,21 +1409,169 @@ public void Should_Throw_If_Column_Is_Set_But_No_Line() providerName)); // Then - result.IsArgumentOutOfRangeException("column"); + result.IsArgumentOutOfRangeException("endLine"); + } + + [Fact] + public void Should_Throw_If_EndLine_Is_Smaller_Line() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 100; + var endLine = 12; + int? column = null; + int? endColumn = null; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var result = Record.Exception(() => + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("endLine"); + } + + [Fact] + public void Should_Handle_EndLine_Which_Is_Null() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + int? endLine = null; + int? column = null; + int? endColumn = null; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var issue = + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName); + + // Then + issue.EndLine.ShouldBe(endLine); + } + + [Fact] + public void Should_Handle_EndLine_Which_Is_Equals_Line() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 10; + int? column = null; + int? endColumn = null; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var issue = + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName); + + // Then + issue.EndLine.ShouldBe(endLine); } [Theory] - [InlineData(null)] [InlineData(1)] [InlineData(int.MaxValue)] - public void Should_Set_Column(int? column) + public void Should_Set_EndLine(int endLine) { // Given var identifier = "identifier"; var projectPath = @"src\foo.csproj"; var projectName = "foo"; var filePath = @"src\foo.cs"; - var line = 100; + var line = 1; + var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1331,7 +1591,9 @@ public void Should_Set_Column(int? column) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1344,7 +1606,605 @@ public void Should_Set_Column(int? column) providerName); // Then - issue.Column.ShouldBe(column); + issue.EndLine.ShouldBe(endLine); + } + } + + public sealed class TheColumnArgument + { + [Fact] + public void Should_Throw_If_Column_Is_Negative() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + var column = -1; + int? endColumn = null; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var result = Record.Exception(() => + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("column"); + } + + [Fact] + public void Should_Throw_If_Column_Is_Zero() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + var column = 0; + int? endColumn = null; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var result = Record.Exception(() => + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("column"); + } + + [Fact] + public void Should_Throw_If_Column_Is_Set_But_No_Line() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + int? line = null; + int? endLine = null; + var column = 50; + int? endColumn = null; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var result = Record.Exception(() => + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("column"); + } + + [Fact] + public void Should_Handle_Column_Which_Is_Null() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + int? column = null; + int? endColumn = null; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var issue = + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName); + + // Then + issue.Column.ShouldBe(column); + } + + [Theory] + [InlineData(null)] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void Should_Set_Column(int? column) + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + int? endColumn = null; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var issue = + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName); + + // Then + issue.Column.ShouldBe(column); + } + } + + public sealed class TheEndColumnArgument + { + [Fact] + public void Should_Throw_If_EndColumn_Is_Negative() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + var column = 50; + var endColumn = -1; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var result = Record.Exception(() => + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("endColumn"); + } + + [Fact] + public void Should_Throw_If_EndColumn_Is_Zero() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + var column = 50; + var endColumn = 0; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var result = Record.Exception(() => + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("endColumn"); + } + + [Fact] + public void Should_Throw_If_EndColumn_Is_Set_But_No_Column() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + int? column = null; + var endColumn = 55; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var result = Record.Exception(() => + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("endColumn"); + } + + [Fact] + public void Should_Throw_If_EndColumn_Is_Smaller_Column() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + var column = 50; + var endColumn = 5; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var result = Record.Exception(() => + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName)); + + // Then + result.IsArgumentOutOfRangeException("endColumn"); + } + + [Fact] + public void Should_Handle_EndColumn_Which_Is_Null() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + int? column = null; + int? endColumn = null; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var issue = + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName); + + // Then + issue.EndColumn.ShouldBe(endColumn); + } + + [Fact] + public void Should_Handle_EndColumn_Which_Is_Equals_Column() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + var column = 50; + var endColumn = 50; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var issue = + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName); + + // Then + issue.EndColumn.ShouldBe(endColumn); + } + + [Theory] + [InlineData(null)] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void Should_Set_EndColumn(int? endColumn) + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + var column = 1; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var issue = + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName); + + // Then + issue.EndColumn.ShouldBe(endColumn); } } @@ -1359,7 +2219,9 @@ public void Should_Throw_If_MessageText_Is_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; string messageText = null; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1379,7 +2241,9 @@ public void Should_Throw_If_MessageText_Is_Null() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1404,7 +2268,9 @@ public void Should_Throw_If_MessageText_Is_Empty() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = string.Empty; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1424,7 +2290,9 @@ public void Should_Throw_If_MessageText_Is_Empty() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1449,7 +2317,9 @@ public void Should_Throw_If_MessageText_Is_WhiteSpace() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = " "; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1469,7 +2339,9 @@ public void Should_Throw_If_MessageText_Is_WhiteSpace() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1495,7 +2367,9 @@ public void Should_Set_MessageText(string messageText) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; var priority = 1; @@ -1514,7 +2388,9 @@ public void Should_Set_MessageText(string messageText) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1546,7 +2422,9 @@ public void Should_Set_MessageHtml(string messageHtml) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageMarkdown = "MessageMarkdown"; var priority = 1; @@ -1565,7 +2443,9 @@ public void Should_Set_MessageHtml(string messageHtml) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1597,7 +2477,9 @@ public void Should_Set_MessageHtml(string messageMarkdown) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var priority = 1; @@ -1616,7 +2498,9 @@ public void Should_Set_MessageHtml(string messageMarkdown) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1650,7 +2534,9 @@ public void Should_Set_Priority(int? priority) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1669,7 +2555,9 @@ public void Should_Set_Priority(int? priority) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1697,7 +2585,9 @@ public void Should_Handle_PriorityNames_Which_Are_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1717,7 +2607,9 @@ public void Should_Handle_PriorityNames_Which_Are_Null() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1742,7 +2634,9 @@ public void Should_Handle_PriorityNames_Which_Are_Empty() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1762,7 +2656,9 @@ public void Should_Handle_PriorityNames_Which_Are_Empty() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1787,7 +2683,9 @@ public void Should_Handle_PriorityNames_Which_Are_WhiteSpace() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1807,7 +2705,9 @@ public void Should_Handle_PriorityNames_Which_Are_WhiteSpace() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1833,7 +2733,9 @@ public void Should_Set_Priority_Name(string priorityName) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1852,7 +2754,9 @@ public void Should_Set_Priority_Name(string priorityName) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1883,7 +2787,9 @@ public void Should_Set_Rule(string rule) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1902,7 +2808,9 @@ public void Should_Set_Rule(string rule) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1930,7 +2838,9 @@ public void Should_Set_Rule_Url() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1950,7 +2860,9 @@ public void Should_Set_Rule_Url() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -1975,7 +2887,9 @@ public void Should_Set_Rule_Url_If_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1995,7 +2909,9 @@ public void Should_Set_Rule_Url_If_Null() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -2026,7 +2942,9 @@ public void Should_Set_Run(string run) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2045,7 +2963,9 @@ public void Should_Set_Run(string run) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -2073,7 +2993,9 @@ public void Should_Throw_If_Provider_Type_Is_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2093,7 +3015,9 @@ public void Should_Throw_If_Provider_Type_Is_Null() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -2118,7 +3042,9 @@ public void Should_Throw_If_Provider_Type_Is_Empty() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2138,7 +3064,9 @@ public void Should_Throw_If_Provider_Type_Is_Empty() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -2163,7 +3091,9 @@ public void Should_Throw_If_Provider_Type_Is_WhiteSpace() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2183,7 +3113,9 @@ public void Should_Throw_If_Provider_Type_Is_WhiteSpace() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -2209,7 +3141,9 @@ public void Should_Set_ProviderType(string providerType) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2228,7 +3162,9 @@ public void Should_Set_ProviderType(string providerType) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -2256,7 +3192,9 @@ public void Should_Throw_If_Provider_Name_Is_Null() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2276,7 +3214,9 @@ public void Should_Throw_If_Provider_Name_Is_Null() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -2301,7 +3241,9 @@ public void Should_Throw_If_Provider_Name_Is_Empty() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2321,7 +3263,9 @@ public void Should_Throw_If_Provider_Name_Is_Empty() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -2346,7 +3290,9 @@ public void Should_Throw_If_Provider_Name_Is_WhiteSpace() var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2366,7 +3312,9 @@ public void Should_Throw_If_Provider_Name_Is_WhiteSpace() projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, @@ -2392,7 +3340,9 @@ public void Should_Set_ProviderName(string providerName) var projectName = "foo"; var filePath = @"src\foo.cs"; var line = 10; + var endLine = 12; var column = 50; + var endColumn = 55; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2411,7 +3361,9 @@ public void Should_Set_ProviderName(string providerName) projectName, filePath, line, + endLine, column, + endColumn, messageText, messageHtml, messageMarkdown, diff --git a/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs b/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs index 15bb98575..2f24d8c0b 100644 --- a/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs +++ b/src/Cake.Issues.Tests/Serialization/IssueDeserializationExtensionsTests.cs @@ -150,7 +150,7 @@ public void Should_Return_IssueV3() .WithMessageInHtmlFormat("Something went wrong.") .WithMessageInMarkdownFormat("Something went **wrong**.") .InProject(@"src\Foo\Bar.csproj", "Bar") - .InFile(@"src\Foo\Bar.cs", 42, 23) + .InFile(@"src\Foo\Bar.cs", 42, 420, 23, 230) .OfRule("Rule", new Uri("https://google.com")) .WithPriority(IssuePriority.Warning)); } @@ -273,7 +273,7 @@ public void Should_Return_List_Of_IssuesV3() .WithMessageInHtmlFormat("Something went wrong.") .WithMessageInMarkdownFormat("Something went **wrong**.") .InProject(@"src\Foo\Bar.csproj", "Bar") - .InFile(@"src\Foo\Bar.cs", 42, 23) + .InFile(@"src\Foo\Bar.cs", 42, 420, 23, 230) .OfRule("Rule", new Uri("https://google.com")) .WithPriority(IssuePriority.Warning)); IssueChecker.Check( diff --git a/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs b/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs index e5949382a..634d01649 100644 --- a/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs +++ b/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs @@ -220,6 +220,24 @@ public void Should_Give_Correct_Result_For_Line_After_Roundtrip() result.Line.ShouldBe(line); } + [Fact] + public void Should_Give_Correct_Result_For_EndLine_After_Roundtrip() + { + // Given + var endLine = 420; + var issue = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile(@"src/foo.bar", 42, endLine, null, null) + .Create(); + + // When + var result = issue.SerializeToJsonString().DeserializeToIssue(); + + // Then + result.EndLine.ShouldBe(endLine); + } + [Fact] public void Should_Give_Correct_Result_For_Column_After_Roundtrip() { @@ -238,6 +256,24 @@ public void Should_Give_Correct_Result_For_Column_After_Roundtrip() result.Column.ShouldBe(column); } + [Fact] + public void Should_Give_Correct_Result_For_EndColumn_After_Roundtrip() + { + // Given + var endColumn = 230; + var issue = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile(@"src/foo.bar", 42, 420, 23, endColumn) + .Create(); + + // When + var result = issue.SerializeToJsonString().DeserializeToIssue(); + + // Then + result.EndColumn.ShouldBe(endColumn); + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { @@ -626,6 +662,34 @@ public void Should_Give_Correct_Result_For_Line_After_Roundtrip() result.Last().Line.ShouldBe(line2); } + [Fact] + public void Should_Give_Correct_Result_For_EndLine_After_Roundtrip() + { + // Given + var endLine1 = 230; + var endLine2 = 420; + var issues = + new List + { + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .InFile(@"src/foo.bar", 23, endLine1, null, null) + .Create(), + IssueBuilder + .NewIssue("message2", "providerType2", "providerName2") + .InFile(@"src/foo.bar", 42, endLine2, null, null) + .Create(), + }; + + // When + var result = issues.SerializeToJsonString().DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().EndLine.ShouldBe(endLine1); + result.Last().EndLine.ShouldBe(endLine2); + } + [Fact] public void Should_Give_Correct_Result_For_Column_After_Roundtrip() { @@ -654,6 +718,34 @@ public void Should_Give_Correct_Result_For_Column_After_Roundtrip() result.Last().Column.ShouldBe(column2); } + [Fact] + public void Should_Give_Correct_Result_For_EndColumn_After_Roundtrip() + { + // Given + var endColumn1 = 230; + var endColumn2 = 420; + var issues = + new List + { + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .InFile(@"src/foo.bar", 5, 50, 23, endColumn1) + .Create(), + IssueBuilder + .NewIssue("message2", "providerType2", "providerName2") + .InFile(@"src/foo.bar", 5, 50, 42, endColumn2) + .Create(), + }; + + // When + var result = issues.SerializeToJsonString().DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().EndColumn.ShouldBe(endColumn1); + result.Last().EndColumn.ShouldBe(endColumn2); + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { @@ -1126,6 +1218,36 @@ public void Should_Give_Correct_Result_For_Line_After_Roundtrip() } } + [Fact] + public void Should_Give_Correct_Result_For_EndLine_After_Roundtrip() + { + // Given + var endLine = 420; + var issue = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile(@"src/foo.bar", 42, endLine, null, null) + .Create(); + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issue.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssue(); + + // Then + result.EndLine.ShouldBe(endLine); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_Column_After_Roundtrip() { @@ -1156,6 +1278,36 @@ public void Should_Give_Correct_Result_For_Column_After_Roundtrip() } } + [Fact] + public void Should_Give_Correct_Result_For_EndColumn_After_Roundtrip() + { + // Given + var endColumn = 230; + var issue = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .InFile(@"src/foo.bar", 42, 50, 1, endColumn) + .Create(); + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issue.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssue(); + + // Then + result.EndColumn.ShouldBe(endColumn); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { @@ -1739,6 +1891,46 @@ public void Should_Give_Correct_Result_For_Line_After_Roundtrip() } } + [Fact] + public void Should_Give_Correct_Result_For_EndLine_After_Roundtrip() + { + // Given + var endLine1 = 230; + var endLine2 = 420; + var issues = + new List + { + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .InFile(@"src/foo.bar", 23, endLine1, null, null) + .Create(), + IssueBuilder + .NewIssue("message2", "providerType2", "providerName2") + .InFile(@"src/foo.bar", 42, endLine2, null, null) + .Create(), + }; + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issues.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().EndLine.ShouldBe(endLine1); + result.Last().EndLine.ShouldBe(endLine2); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_Column_After_Roundtrip() { @@ -1779,6 +1971,46 @@ public void Should_Give_Correct_Result_For_Column_After_Roundtrip() } } + [Fact] + public void Should_Give_Correct_Result_For_EndColumn_After_Roundtrip() + { + // Given + var endColumn1 = 23; + var endColumn2 = 42; + var issues = + new List + { + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .InFile(@"src/foo.bar", 5, 50, 1, endColumn1) + .Create(), + IssueBuilder + .NewIssue("message2", "providerType2", "providerName2") + .InFile(@"src/foo.bar", 5, 50, 1, endColumn2) + .Create(), + }; + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issues.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().EndColumn.ShouldBe(endColumn1); + result.Last().EndColumn.ShouldBe(endColumn2); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { diff --git a/src/Cake.Issues.Tests/Testfiles/issueV3.json b/src/Cake.Issues.Tests/Testfiles/issueV3.json index 0c4d07046..94191f89a 100644 --- a/src/Cake.Issues.Tests/Testfiles/issueV3.json +++ b/src/Cake.Issues.Tests/Testfiles/issueV3.json @@ -1,9 +1,11 @@ { "Version": 3, - "Identifier": "Identifier", + "Identifier": "Identifier", "AffectedFileRelativePath": "src\/Foo\/Bar.cs", "Line": 42, + "EndLine": 420, "Column": 23, + "EndColumn": 230, "MessageText": "Something went wrong.", "MessageHtml": "Something went wrong.", "MessageMarkdown": "Something went **wrong**.", @@ -13,7 +15,7 @@ "ProjectName": "Bar", "ProviderName": "Test Provider", "ProviderType": "TestProvider", - "Run": "TestRun", + "Run": "TestRun", "Rule": "Rule", "RuleUrl": "https://google.com" } \ No newline at end of file diff --git a/src/Cake.Issues.Tests/Testfiles/issuesV3.json b/src/Cake.Issues.Tests/Testfiles/issuesV3.json index 1c79f4ae4..d3099e26e 100644 --- a/src/Cake.Issues.Tests/Testfiles/issuesV3.json +++ b/src/Cake.Issues.Tests/Testfiles/issuesV3.json @@ -4,7 +4,9 @@ "Identifier": "Identifier1", "AffectedFileRelativePath": "src\/Foo\/Bar.cs", "Line": 42, + "EndLine": 420, "Column": 23, + "EndColumn": 230, "MessageText": "Something went wrong.", "MessageHtml": "Something went wrong.", "MessageMarkdown": "Something went **wrong**.", @@ -22,7 +24,9 @@ "Identifier": "Identifier2", "AffectedFileRelativePath": "src\/Foo\/Bar2.cs", "Line": null, + "EndLine": null, "Column": null, + "EndColumn": null, "MessageText": "Something went wrong again.", "MessageHtml": "Something went wrong again.", "MessageMarkdown": "Something went **wrong** again.", diff --git a/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs b/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs index 57b9b3bd5..9e107eab3 100644 --- a/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs +++ b/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs @@ -20,7 +20,9 @@ public IssueCheckerFixture(string identifier, string messageText, string provide this.ProjectName = "ProjectName"; this.AffectedFileRelativePath = @"src\source.file"; this.Line = 42; + this.EndLine = 420; this.Column = 23; + this.EndColumn = 230; this.MessageText = messageText; this.MessageHtml = "messageHtml"; this.MessageMarkdown = "messageMarkdown"; @@ -34,7 +36,7 @@ public IssueCheckerFixture(string identifier, string messageText, string provide .WithMessageInHtmlFormat(this.MessageHtml) .WithMessageInMarkdownFormat(this.MessageMarkdown) .InProject(this.ProjectFileRelativePath, this.ProjectName) - .InFile(this.AffectedFileRelativePath, this.Line, this.Column) + .InFile(this.AffectedFileRelativePath, this.Line, this.EndLine, this.Column, this.EndColumn) .OfRule(this.Rule, this.RuleUrl) .WithPriority(this.Priority, this.PriorityName); @@ -60,8 +62,12 @@ public IssueCheckerFixture(string identifier, string messageText, string provide public int Line { get; private set; } + public int EndLine { get; private set; } + public int Column { get; private set; } + public int EndColumn { get; private set; } + public string MessageText { get; private set; } public string MessageHtml { get; private set; } diff --git a/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs b/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs index ba8f252f3..c95545a63 100644 --- a/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs +++ b/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs @@ -150,7 +150,9 @@ public void Should_Throw_If_Issue_Is_Null() fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -180,7 +182,9 @@ public void Should_Not_Throw_If_All_Values_Are_The_Same() fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -214,7 +218,9 @@ public void Should_Throw_If_ProviderType_Is_Different(string expectedValue, stri fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -250,7 +256,9 @@ public void Should_Throw_If_ProviderName_Is_Different(string expectedValue, stri fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -290,7 +298,9 @@ public void Should_Throw_If_Run_Is_Different(string expectedValue, string actual fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -326,7 +336,9 @@ public void Should_Throw_If_Identifier_Is_Different(string expectedValue, string fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -363,7 +375,9 @@ public void Should_Throw_If_ProjectFileRelativePath_Is_Different(string expected fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -403,7 +417,9 @@ public void Should_Throw_If_ProjectName_Is_Different(string expectedValue, strin expectedValue, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -440,7 +456,9 @@ public void Should_Throw_If_AffectedFileRelativePath_Is_Different(string expecte fixture.ProjectName, expectedValue, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -464,7 +482,7 @@ public void Should_Throw_If_Line_Is_Different(int? expectedValue, int? actualVal var fixture = new IssueCheckerFixture(); var issue = fixture.IssueBuilder - .InFile(fixture.AffectedFileRelativePath, actualValue, null) + .InFile(fixture.AffectedFileRelativePath, actualValue) .Create(); // When @@ -480,6 +498,8 @@ public void Should_Throw_If_Line_Is_Different(int? expectedValue, int? actualVal fixture.AffectedFileRelativePath, expectedValue, null, + null, + null, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -493,6 +513,47 @@ public void Should_Throw_If_Line_Is_Different(int? expectedValue, int? actualVal result.Message.ShouldStartWith("Expected issue.Line"); } + [Theory] + [InlineData(420, 230)] + [InlineData(null, 420)] + [InlineData(420, null)] + public void Should_Throw_If_EndLine_Is_Different(int? expectedValue, int? actualValue) + { + // Given + var fixture = new IssueCheckerFixture(); + var issue = + fixture.IssueBuilder + .InFile(fixture.AffectedFileRelativePath, fixture.Line, actualValue, fixture.Column, fixture.EndColumn) + .Create(); + + // When + var result = Record.Exception(() => + IssueChecker.Check( + issue, + fixture.ProviderType, + fixture.ProviderName, + fixture.Run, + fixture.Identifier, + fixture.ProjectFileRelativePath, + fixture.ProjectName, + fixture.AffectedFileRelativePath, + fixture.Line, + expectedValue, + fixture.Column, + fixture.EndColumn, + fixture.MessageText, + fixture.MessageHtml, + fixture.MessageMarkdown, + fixture.Priority, + fixture.PriorityName, + fixture.Rule, + fixture.RuleUrl)); + + // Then + result.ShouldBeOfType(); + result.Message.ShouldStartWith("Expected issue.EndLine"); + } + [Theory] [InlineData(42, 23)] [InlineData(null, 42)] @@ -503,7 +564,7 @@ public void Should_Throw_If_Column_Is_Different(int? expectedValue, int? actualV var fixture = new IssueCheckerFixture(); var issue = fixture.IssueBuilder - .InFile(fixture.AffectedFileRelativePath, fixture.Line, actualValue) + .InFile(fixture.AffectedFileRelativePath, fixture.Line, fixture.EndLine, actualValue, null) .Create(); // When @@ -518,7 +579,9 @@ public void Should_Throw_If_Column_Is_Different(int? expectedValue, int? actualV fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, expectedValue, + null, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -532,6 +595,47 @@ public void Should_Throw_If_Column_Is_Different(int? expectedValue, int? actualV result.Message.ShouldStartWith("Expected issue.Column"); } + [Theory] + [InlineData(42, 23)] + [InlineData(null, 42)] + [InlineData(42, null)] + public void Should_Throw_If_EndColumn_Is_Different(int? expectedValue, int? actualValue) + { + // Given + var fixture = new IssueCheckerFixture(); + var issue = + fixture.IssueBuilder + .InFile(fixture.AffectedFileRelativePath, fixture.Line, fixture.EndLine, fixture.Column, actualValue) + .Create(); + + // When + var result = Record.Exception(() => + IssueChecker.Check( + issue, + fixture.ProviderType, + fixture.ProviderName, + fixture.Run, + fixture.Identifier, + fixture.ProjectFileRelativePath, + fixture.ProjectName, + fixture.AffectedFileRelativePath, + fixture.Line, + fixture.EndLine, + fixture.Column, + expectedValue, + fixture.MessageText, + fixture.MessageHtml, + fixture.MessageMarkdown, + fixture.Priority, + fixture.PriorityName, + fixture.Rule, + fixture.RuleUrl)); + + // Then + result.ShouldBeOfType(); + result.Message.ShouldStartWith("Expected issue.EndColumn"); + } + [Theory] [InlineData("Message", "Foo")] [InlineData(null, "Foo")] @@ -554,7 +658,9 @@ public void Should_Throw_If_MessageText_Is_Different(string expectedValue, strin fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, expectedValue, fixture.MessageHtml, fixture.MessageMarkdown, @@ -594,7 +700,9 @@ public void Should_Throw_If_MessageHtml_Is_Different(string expectedValue, strin fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, expectedValue, fixture.MessageMarkdown, @@ -634,7 +742,9 @@ public void Should_Throw_If_MessageMarkdown_Is_Different(string expectedValue, s fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, expectedValue, @@ -671,7 +781,9 @@ public void Should_Throw_If_Priority_Is_Different(IssuePriority expectedValue, I fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -711,7 +823,9 @@ public void Should_Throw_If_PriorityName_Is_Different(string expectedValue, stri fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -751,7 +865,9 @@ public void Should_Throw_If_Rule_Is_Different(string expectedValue, string actua fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -788,7 +904,9 @@ public void Should_Throw_If_RuleUrl_Is_Different(string expectedValue, string ac fixture.ProjectName, fixture.AffectedFileRelativePath, fixture.Line, + fixture.EndLine, fixture.Column, + fixture.EndColumn, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, diff --git a/src/Cake.Issues/IIssue.cs b/src/Cake.Issues/IIssue.cs index 63754d95e..12c78dee6 100644 --- a/src/Cake.Issues/IIssue.cs +++ b/src/Cake.Issues/IIssue.cs @@ -40,12 +40,24 @@ public interface IIssue /// int? Line { get; } + /// + /// Gets the end of the line range in the file where the issues has occurred. + /// null if the issue affects the whole file, an asssembly or only a single line. + /// + int? EndLine { get; } + /// /// Gets the column in the file where the issues has occurred. /// null if the issue affects the whole file or an asssembly. /// int? Column { get; } + /// + /// Gets the end of the column range in the file where the issues has occurred. + /// null if the issue affects the whole file, an asssembly or only a single column. + /// + int? EndColumn { get; } + /// /// Gets the message of the issue in text format. /// diff --git a/src/Cake.Issues/IIssueComparer.cs b/src/Cake.Issues/IIssueComparer.cs index cb2996cd6..d12925243 100644 --- a/src/Cake.Issues/IIssueComparer.cs +++ b/src/Cake.Issues/IIssueComparer.cs @@ -39,8 +39,14 @@ public IIssueComparer() /// /// /// + /// + /// + /// /// /// + /// + /// + /// /// /// public IIssueComparer(bool compareOnlyPersistentProperties) @@ -67,7 +73,9 @@ public bool Equals(IIssue x, IIssue y) (x.ProjectName == y.ProjectName) && (this.compareOnlyPersistentProperties || x.AffectedFileRelativePath?.FullPath == y.AffectedFileRelativePath?.FullPath) && (this.compareOnlyPersistentProperties || x.Line == y.Line) && + (this.compareOnlyPersistentProperties || x.EndLine == y.EndLine) && (this.compareOnlyPersistentProperties || x.Column == y.Column) && + (this.compareOnlyPersistentProperties || x.EndColumn == y.EndColumn) && (x.MessageText == y.MessageText) && (x.MessageHtml == y.MessageHtml) && (x.MessageMarkdown == y.MessageMarkdown) && @@ -114,7 +122,9 @@ public int GetHashCode(IIssue obj) obj.ProjectName, obj.AffectedFileRelativePath?.ToString(), obj.Line, + obj.EndLine, obj.Column, + obj.EndColumn, obj.MessageText, obj.MessageHtml, obj.MessageMarkdown, diff --git a/src/Cake.Issues/IIssueExtensions.cs b/src/Cake.Issues/IIssueExtensions.cs index 47bb10441..bddc2a009 100644 --- a/src/Cake.Issues/IIssueExtensions.cs +++ b/src/Cake.Issues/IIssueExtensions.cs @@ -148,10 +148,18 @@ public static string FileName(this IIssue issue) /// The value of . /// /// + /// {EndLine} + /// The value of . + /// + /// /// {Column} /// The value of . /// /// + /// {EndColumn} + /// The value of . + /// + /// /// {Rule} /// The value of . /// @@ -200,7 +208,9 @@ public static string ReplaceIssuePattern(this string pattern, IIssue issue) .Replace("{FileDirectory}", issue.FileDirectory()) .Replace("{FileName}", issue.FileName()) .Replace("{Line}", issue.Line?.ToString()) + .Replace("{EndLine}", issue.EndLine?.ToString()) .Replace("{Column}", issue.Column?.ToString()) + .Replace("{EndColumn}", issue.EndColumn?.ToString()) .Replace("{Rule}", issue.Rule) .Replace("{RuleUrl}", issue.RuleUrl?.ToString()) .Replace("{Run}", issue.Run) diff --git a/src/Cake.Issues/Issue.cs b/src/Cake.Issues/Issue.cs index 0ce30d074..eba762e75 100644 --- a/src/Cake.Issues/Issue.cs +++ b/src/Cake.Issues/Issue.cs @@ -23,8 +23,12 @@ public class Issue : IIssue /// null or if issue is not related to a change in a file. /// The line in the file where the issues has occurred. /// null if the issue affects the whole file or an asssembly. + /// The end of the line range in the file where the issues has occurred. + /// null if the issue affects the whole file, an asssembly or only a single line. /// The column in the file where the issues has occurred. /// null if the issue affects the whole file or an asssembly. + /// The end of the column range in the file where the issues has occurred. + /// null if the issue affects the whole file, an asssembly or only a single column. /// The message of the issue in plain text format. /// The message of the issue in Html format. /// The message of the issue in Markdown format. @@ -45,7 +49,9 @@ public Issue( string projectName, string affectedFileRelativePath, int? line, + int? endLine, int? column, + int? endColumn, string messageText, string messageHtml, string messageMarkdown, @@ -59,7 +65,9 @@ public Issue( { identifier.NotNullOrWhiteSpace(nameof(identifier)); line?.NotNegativeOrZero(nameof(line)); + endLine?.NotNegativeOrZero(nameof(endLine)); column?.NotNegativeOrZero(nameof(column)); + endColumn?.NotNegativeOrZero(nameof(endColumn)); messageText.NotNullOrWhiteSpace(nameof(messageText)); providerType.NotNullOrWhiteSpace(nameof(providerType)); providerName.NotNullOrWhiteSpace(nameof(providerName)); @@ -105,15 +113,37 @@ public Issue( throw new ArgumentOutOfRangeException(nameof(line), "Cannot specify a line while not specifying a file."); } - if (!line.HasValue && column.HasValue) + if (!line.HasValue && (column.HasValue || endColumn.HasValue)) { throw new ArgumentOutOfRangeException(nameof(column), $"Cannot specify a column while not specifying a line."); } + if (!line.HasValue && endLine.HasValue) + { + throw new ArgumentOutOfRangeException(nameof(endLine), $"Cannot specify the end of line range while not specifying start of line range."); + } + + if (line.HasValue && endLine.HasValue && line.Value > endLine.Value) + { + throw new ArgumentOutOfRangeException(nameof(endLine), $"Line range needs to end after start of range."); + } + + if (!column.HasValue && endColumn.HasValue) + { + throw new ArgumentOutOfRangeException(nameof(endColumn), $"Cannot specify the end of column range while not specifying start of column range."); + } + + if (column.HasValue && endColumn.HasValue && column.Value > endColumn.Value) + { + throw new ArgumentOutOfRangeException(nameof(endColumn), $"Column range needs to end after start of range."); + } + this.Identifier = identifier; this.ProjectName = projectName; this.Line = line; + this.EndLine = endLine; this.Column = column; + this.EndColumn = endColumn; this.MessageText = messageText; this.MessageHtml = messageHtml; this.MessageMarkdown = messageMarkdown; @@ -141,9 +171,15 @@ public Issue( /// public int? Line { get; } + /// + public int? EndLine { get; } + /// public int? Column { get; } + /// + public int? EndColumn { get; } + /// public string MessageText { get; } diff --git a/src/Cake.Issues/IssueBuilder.cs b/src/Cake.Issues/IssueBuilder.cs index 90ff204f9..ab09271fa 100644 --- a/src/Cake.Issues/IssueBuilder.cs +++ b/src/Cake.Issues/IssueBuilder.cs @@ -17,7 +17,9 @@ public class IssueBuilder private string projectName; private string filePath; private int? line; + private int? endLine; private int? column; + private int? endColumn; private int? priority; private string priorityName; private string rule; @@ -245,8 +247,7 @@ public IssueBuilder InFile(string filePath, int? line) { line?.NotNegativeOrZero(nameof(line)); - this.filePath = filePath; - this.line = line; + this.InFile(filePath, line, null); return this; } @@ -267,9 +268,38 @@ public IssueBuilder InFile(string filePath, int? line, int? column) line?.NotNegativeOrZero(nameof(line)); column?.NotNegativeOrZero(nameof(column)); + this.InFile(filePath, line, null, column, null); + + return this; + } + + /// + /// Sets the path to the file affected by the issue and the line and column in the file where the issues has occurred. + /// + /// The path to the file affacted by the issue. + /// The path needs to be relative to the repository root. + /// null or if issue is not related to a change in a file. + /// The line in the file where the issues has occurred. + /// null if the issue affects the whole file or an asssembly. + /// The end of the line range in the file where the issues has occurred. + /// null if the issue affects the whole file, an asssembly or only a single line. + /// The column in the file where the issues has occurred. + /// null if the issue affects the whole file or an asssembly. + /// The end of the column range in the file where the issues has occurred. + /// null if the issue affects the whole file, an asssembly or only a single column. + /// Issue Builder instance. + public IssueBuilder InFile(string filePath, int? startLine, int? endLine, int? startColumn, int? endColumn) + { + startLine?.NotNegativeOrZero(nameof(startLine)); + endLine?.NotNegativeOrZero(nameof(endLine)); + startColumn?.NotNegativeOrZero(nameof(startColumn)); + endColumn?.NotNegativeOrZero(nameof(endColumn)); + this.filePath = filePath; - this.line = line; - this.column = column; + this.line = startLine; + this.endLine = endLine; + this.column = startColumn; + this.endColumn = endColumn; return this; } @@ -356,7 +386,9 @@ public IIssue Create() this.projectName, this.filePath, this.line, + this.endLine, this.column, + this.endColumn, this.messageText, this.messageHtml, this.messageMarkdown, diff --git a/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs b/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs index 2945a5f08..bbc677b5e 100644 --- a/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs +++ b/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs @@ -85,7 +85,9 @@ internal static SerializableIssueV3 ToSerializableIssue(this IIssue issue) ProjectName = issue.ProjectName, AffectedFileRelativePath = issue.AffectedFileRelativePath?.FullPath, Line = issue.Line, + EndLine = issue.EndLine, Column = issue.Column, + EndColumn = issue.EndColumn, MessageText = issue.MessageText, MessageMarkdown = issue.MessageMarkdown, MessageHtml = issue.MessageHtml, diff --git a/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs b/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs index c4ab1ba43..b5687e06d 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs @@ -33,6 +33,8 @@ internal static Issue ToIssue(this SerializableIssue serializableIssue) serializableIssue.AffectedFileRelativePath, serializableIssue.Line, null, + null, + null, serializableIssue.Message, null, null, diff --git a/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs b/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs index 8e57b6c3a..8ea394204 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs @@ -33,6 +33,8 @@ internal static Issue ToIssue(this SerializableIssueV2 serializableIssue) serializableIssue.AffectedFileRelativePath, serializableIssue.Line, null, + null, + null, serializableIssue.MessageText, serializableIssue.MessageHtml, serializableIssue.MessageMarkdown, diff --git a/src/Cake.Issues/Serialization/SerializableIssueV3.cs b/src/Cake.Issues/Serialization/SerializableIssueV3.cs index 7bc31b02d..9392cd2ce 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV3.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV3.cs @@ -40,10 +40,18 @@ public int Version [DataMember] public int? Line { get; set; } + /// + [DataMember] + public int? EndLine { get; set; } + /// [DataMember] public int? Column { get; set; } + /// + [DataMember] + public int? EndColumn { get; set; } + /// [DataMember] public string MessageText { get; set; } diff --git a/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs b/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs index a1f3c1ebe..f93bd9bea 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs @@ -32,7 +32,9 @@ internal static Issue ToIssue(this SerializableIssueV3 serializableIssue) serializableIssue.ProjectName, serializableIssue.AffectedFileRelativePath, serializableIssue.Line, + serializableIssue.EndLine, serializableIssue.Column, + serializableIssue.EndColumn, serializableIssue.MessageText, serializableIssue.MessageHtml, serializableIssue.MessageMarkdown, From d58b5ac0421694a904ba18000211171f5daa3ad2 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Sat, 4 Jul 2020 21:09:16 +0200 Subject: [PATCH 15/31] (GH-169) Add file link settings --- .../FileLinkSettingsTests.cs | 181 ++++++++++++++++++ src/Cake.Issues.Tests/UriExtensionsTests.cs | 51 +++++ src/Cake.Issues/Aliases.FileLinking.cs | 106 ++++++++++ src/Cake.Issues/FileLinkSettings.cs | 70 +++++++ src/Cake.Issues/IssuesAliasConstants.cs | 5 + src/Cake.Issues/UriExtensions.cs | 36 ++++ 6 files changed, 449 insertions(+) create mode 100644 src/Cake.Issues.Tests/FileLinkSettingsTests.cs create mode 100644 src/Cake.Issues.Tests/UriExtensionsTests.cs create mode 100644 src/Cake.Issues/Aliases.FileLinking.cs create mode 100644 src/Cake.Issues/FileLinkSettings.cs create mode 100644 src/Cake.Issues/UriExtensions.cs diff --git a/src/Cake.Issues.Tests/FileLinkSettingsTests.cs b/src/Cake.Issues.Tests/FileLinkSettingsTests.cs new file mode 100644 index 000000000..a2311f657 --- /dev/null +++ b/src/Cake.Issues.Tests/FileLinkSettingsTests.cs @@ -0,0 +1,181 @@ +namespace Cake.Issues.Tests +{ + using System; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + public sealed class FileLinkSettingsTests + { + public sealed class TheGitHubMethod + { + [Fact] + public void Should_Throw_If_RepositoryUrl_Is_Null() + { + // Given + Uri repositoryUrl = null; + var branch = "master"; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.GitHub(repositoryUrl, branch, rootPath)); + + // Then + result.IsArgumentNullException("repositoryUrl"); + } + + [Fact] + public void Should_Throw_If_Branch_Is_Null() + { + // Given + var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); + string branch = null; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.GitHub(repositoryUrl, branch, rootPath)); + + // Then + result.IsArgumentNullException("branch"); + } + + [Fact] + public void Should_Throw_If_Branch_Is_Empty() + { + // Given + var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); + var branch = string.Empty; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.GitHub(repositoryUrl, branch, rootPath)); + + // Then + result.IsArgumentOutOfRangeException("branch"); + } + + [Fact] + public void Should_Throw_If_Branch_Is_Whitespace() + { + // Given + var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); + var branch = " "; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.GitHub(repositoryUrl, branch, rootPath)); + + // Then + result.IsArgumentOutOfRangeException("branch"); + } + + [Theory] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/{FilePath}#L{Line}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website/", "master", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/{FilePath}#L{Line}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "/foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo/", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo/bar", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/bar/{FilePath}#L{Line}")] + public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string branch, string rootPath, string expectedPattern) + { + // Given + + // When + var result = FileLinkSettings.GitHub(new Uri(repositoryUrl), branch, rootPath); + + // Then + result.FileLinkPattern.ShouldBe(expectedPattern); + } + } + + public sealed class TheAzureDevOpsMethod + { + [Fact] + public void Should_Throw_If_RepositoryUrl_Is_Null() + { + // Given + Uri repositoryUrl = null; + var branch = "master"; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.AzureDevOps(repositoryUrl, branch, rootPath)); + + // Then + result.IsArgumentNullException("repositoryUrl"); + } + + [Fact] + public void Should_Throw_If_Branch_Is_Null() + { + // Given + var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); + string branch = null; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.AzureDevOps(repositoryUrl, branch, rootPath)); + + // Then + result.IsArgumentNullException("branch"); + } + + [Fact] + public void Should_Throw_If_Branch_Is_Empty() + { + // Given + var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); + var branch = string.Empty; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.AzureDevOps(repositoryUrl, branch, rootPath)); + + // Then + result.IsArgumentOutOfRangeException("branch"); + } + + [Fact] + public void Should_Throw_If_Branch_Is_Whitespace() + { + // Given + var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); + var branch = " "; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.AzureDevOps(repositoryUrl, branch, rootPath)); + + // Then + result.IsArgumentOutOfRangeException("branch"); + } + + [Theory] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", null, "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path={FilePath}&version=GBmaster&line={Line}")] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository/", "master", null, "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path={FilePath}&version=GBmaster&line={Line}")] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}")] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "/foo", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}")] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo/", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}")] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo/bar", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/bar/{FilePath}&version=GBmaster&line={Line}")] + [InlineData("https://dev.azure.com/myorganization/_git/myrepo", "master", "foo/bar", "https://dev.azure.com/myorganization/_git/myrepo?path=foo/bar/{FilePath}&version=GBmaster&line={Line}")] + public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string branch, string rootPath, string expectedPattern) + { + // Given + + // When + var result = FileLinkSettings.AzureDevOps(new Uri(repositoryUrl), branch, rootPath); + + // Then + result.FileLinkPattern.ShouldBe(expectedPattern); + } + } + } +} diff --git a/src/Cake.Issues.Tests/UriExtensionsTests.cs b/src/Cake.Issues.Tests/UriExtensionsTests.cs new file mode 100644 index 000000000..6907df88e --- /dev/null +++ b/src/Cake.Issues.Tests/UriExtensionsTests.cs @@ -0,0 +1,51 @@ +namespace Cake.Issues.Tests +{ + using System; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + public sealed class UriExtensionsTests + { + public sealed class TheAppendMethod + { + [Fact] + public void Should_Throw_If_Uri_Is_Null() + { + // Given + Uri uri = null; + var path = "foo"; + + // When + var result = Record.Exception(() => + uri.Append(path)); + + // Then + result.IsArgumentNullException("uri"); + } + + [Theory] + [InlineData("https://google.com/foo/bar", "https://google.com", "foo", "bar")] + [InlineData("https://google.com/foo/bar", "https://google.com/", "foo", "bar")] + [InlineData("https://google.com/foo/bar", "https://google.com", "/foo", "bar")] + [InlineData("https://google.com/foo/bar", "https://google.com", "foo/", "bar")] + [InlineData("https://google.com/foo/bar", "https://google.com", "foo", "/bar")] + [InlineData("https://google.com/foo/bar/", "https://google.com", "foo", "bar/")] + [InlineData("https://google.com/foo/bar", "https://google.com", "foo/", "/bar")] + [InlineData("https://google.com/bar", "https://google.com", null, "bar")] + [InlineData("https://google.com/bar", "https://google.com", "", "bar")] + [InlineData("https://google.com/bar", "https://google.com", " ", "bar")] + [InlineData("https://google.com/bar", "https://google.com", "/", "/bar")] + public void Should_Append_Paths(string expectedPath, string uri, params string[] paths) + { + // Given + + // When + var result = new Uri(uri).Append(paths); + + // Then + result.ToString().ShouldBe(expectedPath); + } + } + } +} diff --git a/src/Cake.Issues/Aliases.FileLinking.cs b/src/Cake.Issues/Aliases.FileLinking.cs new file mode 100644 index 000000000..003c8db6e --- /dev/null +++ b/src/Cake.Issues/Aliases.FileLinking.cs @@ -0,0 +1,106 @@ +namespace Cake.Issues +{ + using System; + using Cake.Core; + using Cake.Core.Annotations; + + /// + /// Contains functionality related to linking to files. + /// + public static partial class Aliases + { + /// + /// Gets an instance of the file link settings for linking files hosted on GitHub. + /// + /// The context. + /// Full URL of the Git repository, + /// eg. https://github.com/cake-contrib/Cake.Issues.Reporting.Generic. + /// Name of the branch. + /// Settings for linking to files hosted in GitHub. + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] + public static FileLinkSettings IssueFileLinkSettingsForGitHub( + this ICakeContext context, + Uri repositoryUrl, + string branch) + { + context.NotNull(nameof(context)); + repositoryUrl.NotNull(nameof(repositoryUrl)); + branch.NotNullOrWhiteSpace(nameof(branch)); + + return context.IssueFileLinkSettingsForGitHub(repositoryUrl, branch, null); + } + + /// + /// Gets an instance of the file link settings for linking files hosted on GitHub in a sub-folder. + /// + /// The context. + /// Full URL of the Git repository, + /// eg. https://github.com/cake-contrib/Cake.Issues.Reporting.Generic. + /// Name of the branch. + /// Root path of the files. + /// null or if files are in the root of the repository. + /// Settings for linking to files hosted in GitHub. + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] + public static FileLinkSettings IssueFileLinkSettingsForGitHub( + this ICakeContext context, + Uri repositoryUrl, + string branch, + string rootPath) + { + context.NotNull(nameof(context)); + repositoryUrl.NotNull(nameof(repositoryUrl)); + branch.NotNullOrWhiteSpace(nameof(branch)); + + return FileLinkSettings.GitHub(repositoryUrl, branch, rootPath); + } + + /// + /// Gets an instance of the file link settings for linking to files hosted in Azure DevOps. + /// + /// The context. + /// Full URL of the Git repository, + /// eg. https://dev.azure.com/myorganization/_git/myrepo. + /// Name of the branch. + /// Settings for linking files hosted on Azure DevOps or Azure DevOps Server. + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] + public static FileLinkSettings IssueFileLinkSettingsForAzureDevOps( + this ICakeContext context, + Uri repositoryUrl, + string branch) + { + context.NotNull(nameof(context)); + repositoryUrl.NotNull(nameof(repositoryUrl)); + branch.NotNullOrWhiteSpace(nameof(branch)); + + return context.IssueFileLinkSettingsForAzureDevOps(repositoryUrl, branch, null); + } + + /// + /// Gets an instance of the file link settings for linking to files hosted in Azure DevOps in a sub-folder. + /// + /// The context. + /// Full URL of the Git repository, + /// eg. https://dev.azure.com/myorganization/_git/myrepo. + /// Name of the branch. + /// Root path of the files. + /// null or if files are in the root of the repository. + /// Settings for linking files hosted on Azure DevOps. + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] + public static FileLinkSettings IssueFileLinkSettingsForAzureDevOps( + this ICakeContext context, + Uri repositoryUrl, + string branch, + string rootPath) + { + context.NotNull(nameof(context)); + repositoryUrl.NotNull(nameof(repositoryUrl)); + branch.NotNullOrWhiteSpace(nameof(branch)); + + return FileLinkSettings.AzureDevOps(repositoryUrl, branch, rootPath); + } + } +} diff --git a/src/Cake.Issues/FileLinkSettings.cs b/src/Cake.Issues/FileLinkSettings.cs new file mode 100644 index 000000000..12c60eed6 --- /dev/null +++ b/src/Cake.Issues/FileLinkSettings.cs @@ -0,0 +1,70 @@ +namespace Cake.Issues +{ + using System; + + /// + /// Settings how issues should be linked to files. + /// + public class FileLinkSettings + { + /// + /// Gets or sets the pattern which should be used to link issues to files. + /// Fields in the form {FieldName} are replaced with the value of the issue. + /// All fields of supported. + /// + public string FileLinkPattern { get; set; } + + /// + /// Returns settings for linking to files hosted in GitHub. + /// + /// Full URL of the Git repository, + /// eg. https://github.com/cake-contrib/Cake.Issues. + /// Name of the branch. + /// Root path of the files. + /// null or if files are in the root of the repository. + /// Settings for linking to files hosted in GitHub. + public static FileLinkSettings GitHub( + Uri repositoryUrl, + string branch, + string rootPath) + { + repositoryUrl.NotNull(nameof(repositoryUrl)); + branch.NotNullOrWhiteSpace(nameof(branch)); + + return new FileLinkSettings() + { + FileLinkPattern = + repositoryUrl.Append("blob", branch, rootPath, "{FilePath}#L{Line}").ToString(), + }; + } + + /// + /// Returns settings for linking to files hosted in Azure DevOps. + /// + /// Full URL of the Git repository, + /// e.g. https://dev.azure.com/myorganization/_git/myrepo. + /// Name of the branch. + /// Root path of the files. + /// null or if files are in the root of the repository. + /// Settings for linking to files hosted in Azure DevOps. + public static FileLinkSettings AzureDevOps( + Uri repositoryUrl, + string branch, + string rootPath) + { + repositoryUrl.NotNull(nameof(repositoryUrl)); + branch.NotNullOrWhiteSpace(nameof(branch)); + + if (!string.IsNullOrWhiteSpace(rootPath)) + { + rootPath = rootPath.Trim('/') + "/"; + } + + return new FileLinkSettings() + { + FileLinkPattern = + repositoryUrl.ToString().TrimEnd('/') + "?path=" + rootPath + "{FilePath}&version=GB" + branch + "&line={Line}", + }; + } + } +} diff --git a/src/Cake.Issues/IssuesAliasConstants.cs b/src/Cake.Issues/IssuesAliasConstants.cs index 4ecf0d797..032efca2d 100644 --- a/src/Cake.Issues/IssuesAliasConstants.cs +++ b/src/Cake.Issues/IssuesAliasConstants.cs @@ -25,6 +25,11 @@ public static class IssuesAliasConstants /// public const string SerializationCakeAliasCategory = "Issue Serialization"; + /// + /// Category to use for all Cake aliases providing functionality for linking to files. + /// + public const string FileLinkingCakeAliasCategory = "File Linking"; + /// /// Category to use for all Cake aliases creating issue providers. /// diff --git a/src/Cake.Issues/UriExtensions.cs b/src/Cake.Issues/UriExtensions.cs new file mode 100644 index 000000000..2d6287cea --- /dev/null +++ b/src/Cake.Issues/UriExtensions.cs @@ -0,0 +1,36 @@ +namespace Cake.Issues +{ + using System; + using System.Globalization; + using System.Linq; + + /// + /// Extensions for the class. + /// + internal static class UriExtensions + { + /// + /// Appends paths to an URI. + /// + /// URI to which the paths should be appended. + /// Paths to append. + /// URI with appended paths. + public static Uri Append(this Uri uri, params string[] paths) + { + uri.NotNull(nameof(uri)); + + return + new Uri( + paths + .Where(x => !string.IsNullOrWhiteSpace(x)) + .Aggregate( + uri.AbsoluteUri, + (current, path) => + string.Format( + CultureInfo.InvariantCulture, + "{0}/{1}", + current.TrimEnd('/'), + path.TrimStart('/')))); + } + } +} From 31b2c7d122b2acf2651b5542a1c6ff375253c0e7 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Mon, 6 Jul 2020 14:33:51 +0200 Subject: [PATCH 16/31] Update release notes link --- nuspec/nuget/Cake.Issues.Testing.nuspec | 2 +- nuspec/nuget/Cake.Issues.nuspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nuspec/nuget/Cake.Issues.Testing.nuspec b/nuspec/nuget/Cake.Issues.Testing.nuspec index 519258325..aaf4fcd4e 100644 --- a/nuspec/nuget/Cake.Issues.Testing.nuspec +++ b/nuspec/nuget/Cake.Issues.Testing.nuspec @@ -17,7 +17,7 @@ Common helpers for testing add-ins based on Cake.Issues Copyright © BBT Software AG and contributors Cake Script Cake-Issues Issues Testing - https://github.com/cake-contrib/Cake.Issues/releases/tag/0.8.1 + https://github.com/cake-contrib/Cake.Issues/releases/tag/0.9.0 diff --git a/nuspec/nuget/Cake.Issues.nuspec b/nuspec/nuget/Cake.Issues.nuspec index 8287bab58..bafece048 100644 --- a/nuspec/nuget/Cake.Issues.nuspec +++ b/nuspec/nuget/Cake.Issues.nuspec @@ -24,7 +24,7 @@ See the Project Site for an overview of the whole ecosystem of addins for workin Copyright © BBT Software AG and contributors Cake Script Cake-Issues CodeAnalysis Linting Issues - https://github.com/cake-contrib/Cake.Issues/releases/tag/0.8.1 + https://github.com/cake-contrib/Cake.Issues/releases/tag/0.9.0 From 10f58cf701f19f42b0d1619b08414edbe5aad80f Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Sun, 12 Jul 2020 00:55:28 +0200 Subject: [PATCH 17/31] Add interfaces for settings --- .../FakeConfigurableIssueProvider.cs | 2 +- src/Cake.Issues.Testing/FakeIssueProvider.cs | 2 +- src/Cake.Issues.Testing/FakeLogFileFormat.cs | 2 +- .../FakeMultiFormatIssueProvider.cs | 2 +- src/Cake.Issues/Aliases.ReadIssues.cs | 4 ++-- src/Cake.Issues/BaseIssueComponent.cs | 2 +- src/Cake.Issues/BaseIssueProvider.cs | 2 +- src/Cake.Issues/BaseLogFileFormat.cs | 2 +- src/Cake.Issues/IBaseIssueComponent.cs | 2 +- src/Cake.Issues/IIssueProvider.cs | 2 +- src/Cake.Issues/ILogFileFormat.cs | 2 +- src/Cake.Issues/IReadIssuesSettings.cs | 15 +++++++++++++++ src/Cake.Issues/IRepositorySettings.cs | 15 +++++++++++++++ src/Cake.Issues/IssuesReader.cs | 4 ++-- src/Cake.Issues/ReadIssuesSettings.cs | 2 +- src/Cake.Issues/RepositorySettings.cs | 2 +- 16 files changed, 46 insertions(+), 16 deletions(-) create mode 100644 src/Cake.Issues/IReadIssuesSettings.cs create mode 100644 src/Cake.Issues/IRepositorySettings.cs diff --git a/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs b/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs index 5a7c9f061..4330764da 100644 --- a/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs +++ b/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs @@ -48,7 +48,7 @@ public FakeConfigurableIssueProvider( /// /// Gets the repository settings. /// - public RepositorySettings RepositorySettings => this.Settings; + public IRepositorySettings RepositorySettings => this.Settings; /// /// Gets the issue provider settings. diff --git a/src/Cake.Issues.Testing/FakeIssueProvider.cs b/src/Cake.Issues.Testing/FakeIssueProvider.cs index 8dcef5169..ae83e6481 100644 --- a/src/Cake.Issues.Testing/FakeIssueProvider.cs +++ b/src/Cake.Issues.Testing/FakeIssueProvider.cs @@ -42,7 +42,7 @@ public FakeIssueProvider(ICakeLog log, IEnumerable issues) /// /// Gets the settings. /// - public new RepositorySettings Settings => base.Settings; + public new IRepositorySettings Settings => base.Settings; /// public override string ProviderName => "Fake Issue Provider"; diff --git a/src/Cake.Issues.Testing/FakeLogFileFormat.cs b/src/Cake.Issues.Testing/FakeLogFileFormat.cs index 8e39bfd73..6d1dbfc90 100644 --- a/src/Cake.Issues.Testing/FakeLogFileFormat.cs +++ b/src/Cake.Issues.Testing/FakeLogFileFormat.cs @@ -42,7 +42,7 @@ public FakeLogFileFormat(ICakeLog log, IEnumerable issues) /// public override IEnumerable ReadIssues( FakeMultiFormatIssueProvider issueProvider, - RepositorySettings repositorySettings, + IRepositorySettings repositorySettings, FakeMultiFormatIssueProviderSettings issueProviderSettings) { return this.issues; diff --git a/src/Cake.Issues.Testing/FakeMultiFormatIssueProvider.cs b/src/Cake.Issues.Testing/FakeMultiFormatIssueProvider.cs index b53d8b55e..3c35c884a 100644 --- a/src/Cake.Issues.Testing/FakeMultiFormatIssueProvider.cs +++ b/src/Cake.Issues.Testing/FakeMultiFormatIssueProvider.cs @@ -26,7 +26,7 @@ public FakeMultiFormatIssueProvider(ICakeLog log, FakeMultiFormatIssueProviderSe /// /// Gets the repository settings. /// - public RepositorySettings RepositorySettings => this.Settings; + public IRepositorySettings RepositorySettings => this.Settings; /// /// Gets the issue provider settings. diff --git a/src/Cake.Issues/Aliases.ReadIssues.cs b/src/Cake.Issues/Aliases.ReadIssues.cs index 1abb5a8d6..d4c653460 100644 --- a/src/Cake.Issues/Aliases.ReadIssues.cs +++ b/src/Cake.Issues/Aliases.ReadIssues.cs @@ -121,7 +121,7 @@ public static IEnumerable ReadIssues( public static IEnumerable ReadIssues( this ICakeContext context, IIssueProvider issueProvider, - ReadIssuesSettings settings) + IReadIssuesSettings settings) { context.NotNull(nameof(context)); issueProvider.NotNull(nameof(issueProvider)); @@ -170,7 +170,7 @@ public static IEnumerable ReadIssues( public static IEnumerable ReadIssues( this ICakeContext context, IEnumerable issueProviders, - ReadIssuesSettings settings) + IReadIssuesSettings settings) { context.NotNull(nameof(context)); settings.NotNull(nameof(settings)); diff --git a/src/Cake.Issues/BaseIssueComponent.cs b/src/Cake.Issues/BaseIssueComponent.cs index 049481873..e56c0f404 100644 --- a/src/Cake.Issues/BaseIssueComponent.cs +++ b/src/Cake.Issues/BaseIssueComponent.cs @@ -8,7 +8,7 @@ /// /// Type of settings. public abstract class BaseIssueComponent : IBaseIssueComponent - where T : RepositorySettings + where T : class, IRepositorySettings { /// /// Initializes a new instance of the class. diff --git a/src/Cake.Issues/BaseIssueProvider.cs b/src/Cake.Issues/BaseIssueProvider.cs index e3eeb928b..3021b9fd9 100644 --- a/src/Cake.Issues/BaseIssueProvider.cs +++ b/src/Cake.Issues/BaseIssueProvider.cs @@ -6,7 +6,7 @@ /// /// Base class for all issue provider implementations. /// - public abstract class BaseIssueProvider : BaseIssueComponent, IIssueProvider + public abstract class BaseIssueProvider : BaseIssueComponent, IIssueProvider { /// /// Initializes a new instance of the class. diff --git a/src/Cake.Issues/BaseLogFileFormat.cs b/src/Cake.Issues/BaseLogFileFormat.cs index facf44245..5c70409e2 100644 --- a/src/Cake.Issues/BaseLogFileFormat.cs +++ b/src/Cake.Issues/BaseLogFileFormat.cs @@ -31,7 +31,7 @@ protected BaseLogFileFormat(ICakeLog log) /// public abstract IEnumerable ReadIssues( TIssueProvider issueProvider, - RepositorySettings repositorySettings, + IRepositorySettings repositorySettings, TSettings issueProviderSettings); } } diff --git a/src/Cake.Issues/IBaseIssueComponent.cs b/src/Cake.Issues/IBaseIssueComponent.cs index 8d10ddc91..435418dac 100644 --- a/src/Cake.Issues/IBaseIssueComponent.cs +++ b/src/Cake.Issues/IBaseIssueComponent.cs @@ -7,7 +7,7 @@ /// /// Type of settings. public interface IBaseIssueComponent - where T : RepositorySettings + where T : IRepositorySettings { /// /// Initializes the component. diff --git a/src/Cake.Issues/IIssueProvider.cs b/src/Cake.Issues/IIssueProvider.cs index dd3231b46..9c71de5dc 100644 --- a/src/Cake.Issues/IIssueProvider.cs +++ b/src/Cake.Issues/IIssueProvider.cs @@ -5,7 +5,7 @@ /// /// Interface describing a provider for issues. /// - public interface IIssueProvider : IBaseIssueComponent + public interface IIssueProvider : IBaseIssueComponent { /// /// Gets the human friendly name of the issue provider. diff --git a/src/Cake.Issues/ILogFileFormat.cs b/src/Cake.Issues/ILogFileFormat.cs index 457bc8f12..663536495 100644 --- a/src/Cake.Issues/ILogFileFormat.cs +++ b/src/Cake.Issues/ILogFileFormat.cs @@ -20,7 +20,7 @@ public interface ILogFileFormat /// List of issues. IEnumerable ReadIssues( TIssueProvider issueProvider, - RepositorySettings repositorySettings, + IRepositorySettings repositorySettings, TSettings issueProviderSettings); } } diff --git a/src/Cake.Issues/IReadIssuesSettings.cs b/src/Cake.Issues/IReadIssuesSettings.cs new file mode 100644 index 000000000..4c22df4df --- /dev/null +++ b/src/Cake.Issues/IReadIssuesSettings.cs @@ -0,0 +1,15 @@ +namespace Cake.Issues +{ + using Cake.Core.IO; + + /// + /// Interface for settings for reading issues. + /// + public interface IReadIssuesSettings : IRepositorySettings + { + /// + /// Gets or sets the name of the run. + /// + string Run { get; set; } + } +} diff --git a/src/Cake.Issues/IRepositorySettings.cs b/src/Cake.Issues/IRepositorySettings.cs new file mode 100644 index 000000000..0ce5a9e87 --- /dev/null +++ b/src/Cake.Issues/IRepositorySettings.cs @@ -0,0 +1,15 @@ +namespace Cake.Issues +{ + using Cake.Core.IO; + + /// + /// Interface for settings containing a path to a repository. + /// + public interface IRepositorySettings + { + /// + /// Gets the Root path of the repository. + /// + DirectoryPath RepositoryRoot { get; } + } +} diff --git a/src/Cake.Issues/IssuesReader.cs b/src/Cake.Issues/IssuesReader.cs index d0a9372ec..349c8f12b 100644 --- a/src/Cake.Issues/IssuesReader.cs +++ b/src/Cake.Issues/IssuesReader.cs @@ -11,7 +11,7 @@ public class IssuesReader { private readonly ICakeLog log; private readonly List issueProviders = new List(); - private readonly ReadIssuesSettings settings; + private readonly IReadIssuesSettings settings; /// /// Initializes a new instance of the class. @@ -22,7 +22,7 @@ public class IssuesReader public IssuesReader( ICakeLog log, IEnumerable issueProviders, - ReadIssuesSettings settings) + IReadIssuesSettings settings) { log.NotNull(nameof(log)); settings.NotNull(nameof(settings)); diff --git a/src/Cake.Issues/ReadIssuesSettings.cs b/src/Cake.Issues/ReadIssuesSettings.cs index f535a9b08..57d378c15 100644 --- a/src/Cake.Issues/ReadIssuesSettings.cs +++ b/src/Cake.Issues/ReadIssuesSettings.cs @@ -5,7 +5,7 @@ /// /// Settings for reading issues. /// - public class ReadIssuesSettings : RepositorySettings + public class ReadIssuesSettings : RepositorySettings, IReadIssuesSettings { /// /// Initializes a new instance of the class. diff --git a/src/Cake.Issues/RepositorySettings.cs b/src/Cake.Issues/RepositorySettings.cs index 24f7e9bb2..81f66e8be 100644 --- a/src/Cake.Issues/RepositorySettings.cs +++ b/src/Cake.Issues/RepositorySettings.cs @@ -5,7 +5,7 @@ /// /// Settings containing a path to a repository. /// - public class RepositorySettings + public class RepositorySettings : IRepositorySettings { /// /// Initializes a new instance of the class. From 30fddc7935d0268c548bc7a595eb9bafc2ac62ff Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Sun, 12 Jul 2020 01:24:43 +0200 Subject: [PATCH 18/31] Fix examples --- src/Cake.Issues/Aliases.ReadIssues.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cake.Issues/Aliases.ReadIssues.cs b/src/Cake.Issues/Aliases.ReadIssues.cs index d4c653460..e961eeed2 100644 --- a/src/Cake.Issues/Aliases.ReadIssues.cs +++ b/src/Cake.Issues/Aliases.ReadIssues.cs @@ -99,13 +99,13 @@ public static IEnumerable ReadIssues( /// The settings. /// Issues reported by issue provider. /// - /// Read issues reported by JetBrains inspect code and format comments in Markdown: + /// Read issues reported by JetBrains inspect code and set run information: /// /// ReadIssues( /// Issues reported by all issue providers. /// /// Read issues reported as MsBuild warnings and issues reported by JetBrains inspect code - /// with comments formatted as Markdown: + /// and set run information: /// /// Date: Sun, 19 Jul 2020 17:33:26 +0200 Subject: [PATCH 19/31] Fix comments and usings (#191) --- src/Cake.Issues/IReadIssuesSettings.cs | 2 -- src/Cake.Issues/ReadIssuesSettings.cs | 4 +--- src/Cake.Issues/RepositorySettings.cs | 4 +--- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Cake.Issues/IReadIssuesSettings.cs b/src/Cake.Issues/IReadIssuesSettings.cs index 4c22df4df..02153e250 100644 --- a/src/Cake.Issues/IReadIssuesSettings.cs +++ b/src/Cake.Issues/IReadIssuesSettings.cs @@ -1,7 +1,5 @@ namespace Cake.Issues { - using Cake.Core.IO; - /// /// Interface for settings for reading issues. /// diff --git a/src/Cake.Issues/ReadIssuesSettings.cs b/src/Cake.Issues/ReadIssuesSettings.cs index 57d378c15..6f15dc535 100644 --- a/src/Cake.Issues/ReadIssuesSettings.cs +++ b/src/Cake.Issues/ReadIssuesSettings.cs @@ -16,9 +16,7 @@ public ReadIssuesSettings(DirectoryPath repositoryRoot) { } - /// - /// Gets or sets the name of the run. - /// + /// public string Run { get; set; } } } diff --git a/src/Cake.Issues/RepositorySettings.cs b/src/Cake.Issues/RepositorySettings.cs index 81f66e8be..e045200fb 100644 --- a/src/Cake.Issues/RepositorySettings.cs +++ b/src/Cake.Issues/RepositorySettings.cs @@ -18,9 +18,7 @@ public RepositorySettings(DirectoryPath repositoryRoot) this.RepositoryRoot = repositoryRoot; } - /// - /// Gets the Root path of the repository. - /// + /// public DirectoryPath RepositoryRoot { get; } } } From 9752e8557714da4e2d5a81a596b6cf07f1e628fe Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Sun, 19 Jul 2020 17:49:56 +0200 Subject: [PATCH 20/31] Add GetFileLink extension to resolve file link URL (#189) --- src/Cake.Issues/FileLinkSettings.cs | 4 ++- src/Cake.Issues/FileLinkSettingsExtensions.cs | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/Cake.Issues/FileLinkSettingsExtensions.cs diff --git a/src/Cake.Issues/FileLinkSettings.cs b/src/Cake.Issues/FileLinkSettings.cs index 12c60eed6..ab7b0675d 100644 --- a/src/Cake.Issues/FileLinkSettings.cs +++ b/src/Cake.Issues/FileLinkSettings.cs @@ -10,7 +10,9 @@ public class FileLinkSettings /// /// Gets or sets the pattern which should be used to link issues to files. /// Fields in the form {FieldName} are replaced with the value of the issue. - /// All fields of supported. + /// All fields of are supported. + /// See + /// to receive the resolved URL to the file. /// public string FileLinkPattern { get; set; } diff --git a/src/Cake.Issues/FileLinkSettingsExtensions.cs b/src/Cake.Issues/FileLinkSettingsExtensions.cs new file mode 100644 index 000000000..4ac21f6cd --- /dev/null +++ b/src/Cake.Issues/FileLinkSettingsExtensions.cs @@ -0,0 +1,25 @@ +namespace Cake.Issues +{ + using System; + + /// + /// Extensions for . + /// + public static class FileLinkSettingsExtensions + { + /// + /// Returns the URL to the file on the source code hosting system + /// defined by for the issue . + /// + /// Settings describing the source code hosting. + /// Issue for which the link should be returned. + /// URL to the file on the source code hosting system. + public static Uri GetFileLink(this FileLinkSettings settings, IIssue issue) + { + settings.NotNull(nameof(settings)); + issue.NotNull(nameof(issue)); + + return new Uri(settings.FileLinkPattern.ReplaceIssuePattern(issue)); + } + } +} From 4dc2e86c41d618715ff71d5c5b708714f85e589e Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Sun, 19 Jul 2020 18:00:27 +0200 Subject: [PATCH 21/31] Make FileLinkSettings.FileLinkPattern readonly (#190) --- src/Cake.Issues/FileLinkSettings.cs | 31 ++++++++++++++++++----------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/Cake.Issues/FileLinkSettings.cs b/src/Cake.Issues/FileLinkSettings.cs index ab7b0675d..e815f08dc 100644 --- a/src/Cake.Issues/FileLinkSettings.cs +++ b/src/Cake.Issues/FileLinkSettings.cs @@ -8,13 +8,24 @@ public class FileLinkSettings { /// - /// Gets or sets the pattern which should be used to link issues to files. + /// Initializes a new instance of the class. + /// + /// Pattern which should be used to link issues to files. + public FileLinkSettings(string fileLinkPattern) + { + fileLinkPattern.NotNullOrWhiteSpace(nameof(fileLinkPattern)); + + this.FileLinkPattern = fileLinkPattern; + } + + /// + /// Gets the pattern which should be used to link issues to files. /// Fields in the form {FieldName} are replaced with the value of the issue. /// All fields of are supported. /// See /// to receive the resolved URL to the file. /// - public string FileLinkPattern { get; set; } + public string FileLinkPattern { get; } /// /// Returns settings for linking to files hosted in GitHub. @@ -33,11 +44,9 @@ public static FileLinkSettings GitHub( repositoryUrl.NotNull(nameof(repositoryUrl)); branch.NotNullOrWhiteSpace(nameof(branch)); - return new FileLinkSettings() - { - FileLinkPattern = - repositoryUrl.Append("blob", branch, rootPath, "{FilePath}#L{Line}").ToString(), - }; + return + new FileLinkSettings( + repositoryUrl.Append("blob", branch, rootPath, "{FilePath}#L{Line}").ToString()); } /// @@ -62,11 +71,9 @@ public static FileLinkSettings AzureDevOps( rootPath = rootPath.Trim('/') + "/"; } - return new FileLinkSettings() - { - FileLinkPattern = - repositoryUrl.ToString().TrimEnd('/') + "?path=" + rootPath + "{FilePath}&version=GB" + branch + "&line={Line}", - }; + return + new FileLinkSettings( + repositoryUrl.ToString().TrimEnd('/') + "?path=" + rootPath + "{FilePath}&version=GB" + branch + "&line={Line}"); } } } From ba8d445f33205825f13410bd81c19ef3ee9c1dd7 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Tue, 28 Jul 2020 20:22:50 +0200 Subject: [PATCH 22/31] Fix test name (#193) --- src/Cake.Issues.Tests/IIssueComparerTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cake.Issues.Tests/IIssueComparerTests.cs b/src/Cake.Issues.Tests/IIssueComparerTests.cs index 675b7ce26..1f76e7eea 100644 --- a/src/Cake.Issues.Tests/IIssueComparerTests.cs +++ b/src/Cake.Issues.Tests/IIssueComparerTests.cs @@ -292,7 +292,7 @@ public void Should_Return_False_If_Rule_Is_Different(string rule1, string rule2) [InlineData("http://foo", "http://bar")] [InlineData("http://foo", null)] [InlineData(null, "http://foo")] - public void Should_Return_False_If_RuleUlr_Is_Different(string ruleUrl1, string ruleUrl2) + public void Should_Return_False_If_RuleUrl_Is_Different(string ruleUrl1, string ruleUrl2) { // Given var issueBuilder = @@ -665,7 +665,7 @@ public void Should_Return_True_If_Rule_Is_Same(string rule1, string rule2) [InlineData("http://foo", "http://foo")] [InlineData("http://foo", "http://Foo")] [InlineData(null, null)] - public void Should_Return_True_If_RuleUlr_Is_Same(string ruleUrl1, string ruleUrl2) + public void Should_Return_True_If_RuleUrl_Is_Same(string ruleUrl1, string ruleUrl2) { // Given var issueBuilder = @@ -988,7 +988,7 @@ public void Should_Return_False_If_Rule_Is_Different(string rule1, string rule2) [InlineData("http://foo", "http://bar")] [InlineData("http://foo", null)] [InlineData(null, "http://foo")] - public void Should_Return_False_If_RuleUlr_Is_Different(string ruleUrl1, string ruleUrl2) + public void Should_Return_False_If_RuleUrl_Is_Different(string ruleUrl1, string ruleUrl2) { // Given var issueBuilder = @@ -1455,7 +1455,7 @@ public void Should_Return_True_If_Rule_Is_Same(string rule1, string rule2) [InlineData("http://foo", "http://foo")] [InlineData("http://foo", "http://Foo")] [InlineData(null, null)] - public void Should_Return_True_If_RuleUlr_Is_Same(string ruleUrl1, string ruleUrl2) + public void Should_Return_True_If_RuleUrl_Is_Same(string ruleUrl1, string ruleUrl2) { // Given var issueBuilder = From bece6c4f37e81b340229943e5af5bbeb2b474da7 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Fri, 31 Jul 2020 21:51:29 +0200 Subject: [PATCH 23/31] (GH-188) Add IIssue.FileLink and pass FileLink settings to issue providers (#192) * (GH-188) Add possibility to pass file link settings while reading issues * (GH-188) Add IIssue.FileLink --- .../BaseIssueProviderFixture.cs | 10 +- .../FakeConfigurableIssueProvider.cs | 2 +- src/Cake.Issues.Testing/FakeIssueProvider.cs | 2 +- src/Cake.Issues.Testing/IssueChecker.cs | 10 + .../BaseMultiFormatIssueProviderTests.cs | 2 +- src/Cake.Issues.Tests/IIssueComparerTests.cs | 140 ++++++++++ .../IIssueExtensionsTests.cs | 2 + src/Cake.Issues.Tests/IssueBuilderTests.cs | 32 +++ src/Cake.Issues.Tests/IssueReaderTests.cs | 53 ++++ src/Cake.Issues.Tests/IssueTests.cs | 239 ++++++++++++++++++ .../IssueSerializationExtensionsTests.cs | 116 +++++++++ ...seConfigurableIssueProviderFixtureTests.cs | 6 +- .../Testing/BaseIssueProviderFixtureTests.cs | 6 +- ...aseMultiFormatIssueProviderFixtureTests.cs | 6 +- .../Testing/IssueCheckerFixture.cs | 4 + .../Testing/IssueCheckerTests.cs | 61 +++++ src/Cake.Issues/BaseIssueProvider.cs | 7 +- .../BaseMultiFormatIssueProvider.cs | 2 +- src/Cake.Issues/IIssue.cs | 6 + src/Cake.Issues/IIssueComparer.cs | 5 + src/Cake.Issues/IIssueExtensions.cs | 5 + src/Cake.Issues/IIssueProvider.cs | 2 +- src/Cake.Issues/IReadIssuesSettings.cs | 5 + src/Cake.Issues/Issue.cs | 7 + src/Cake.Issues/IssueBuilder.cs | 16 ++ src/Cake.Issues/IssuesReader.cs | 10 +- src/Cake.Issues/ReadIssuesSettings.cs | 3 + .../IssueSerializationExtensions.cs | 1 + .../SerializableIssueExtensions.cs | 1 + .../SerializableIssueV2Extensions.cs | 1 + .../Serialization/SerializableIssueV3.cs | 4 + .../SerializableIssueV3Extensions.cs | 7 + 32 files changed, 750 insertions(+), 23 deletions(-) diff --git a/src/Cake.Issues.Testing/BaseIssueProviderFixture.cs b/src/Cake.Issues.Testing/BaseIssueProviderFixture.cs index c71f7f198..69b1799ac 100644 --- a/src/Cake.Issues.Testing/BaseIssueProviderFixture.cs +++ b/src/Cake.Issues.Testing/BaseIssueProviderFixture.cs @@ -19,7 +19,7 @@ public abstract class BaseIssueProviderFixture protected BaseIssueProviderFixture() { this.Log = new FakeLog { Verbosity = Verbosity.Normal }; - this.RepositorySettings = new RepositorySettings(@"c:\repo"); + this.ReadIssuesSettings = new ReadIssuesSettings(@"c:\repo"); } /// @@ -30,7 +30,7 @@ protected BaseIssueProviderFixture() /// /// Gets or sets the repository settings. /// - public RepositorySettings RepositorySettings { get; set; } + public ReadIssuesSettings ReadIssuesSettings { get; set; } /// /// Calls . @@ -67,12 +67,12 @@ private T CreateIssueProvider() typeof(T), this.GetCreateIssueProviderArguments().ToArray()); - if (this.RepositorySettings == null) + if (this.ReadIssuesSettings == null) { - throw new InvalidOperationException("No repository settings set."); + throw new InvalidOperationException("No settings for reading issues set."); } - provider.Initialize(this.RepositorySettings); + provider.Initialize(this.ReadIssuesSettings); return provider; } } diff --git a/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs b/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs index 4330764da..dde9af839 100644 --- a/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs +++ b/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs @@ -59,7 +59,7 @@ public FakeConfigurableIssueProvider( public override string ProviderName => "Fake Issue Provider"; /// - protected override IEnumerable InternalReadIssues() + protected override IEnumerable InternalReadIssues(FileLinkSettings fileLinkSettings) { return this.issues; } diff --git a/src/Cake.Issues.Testing/FakeIssueProvider.cs b/src/Cake.Issues.Testing/FakeIssueProvider.cs index ae83e6481..6aefc7f5b 100644 --- a/src/Cake.Issues.Testing/FakeIssueProvider.cs +++ b/src/Cake.Issues.Testing/FakeIssueProvider.cs @@ -48,7 +48,7 @@ public FakeIssueProvider(ICakeLog log, IEnumerable issues) public override string ProviderName => "Fake Issue Provider"; /// - protected override IEnumerable InternalReadIssues() + protected override IEnumerable InternalReadIssues(FileLinkSettings fileLinkSettings) { return this.issues; } diff --git a/src/Cake.Issues.Testing/IssueChecker.cs b/src/Cake.Issues.Testing/IssueChecker.cs index 9f5007d93..49a4b26a6 100644 --- a/src/Cake.Issues.Testing/IssueChecker.cs +++ b/src/Cake.Issues.Testing/IssueChecker.cs @@ -50,6 +50,7 @@ public static void Check( expectedIssue.EndLine, expectedIssue.Column, expectedIssue.EndColumn, + expectedIssue.FileLink, expectedIssue.MessageText, expectedIssue.MessageHtml, expectedIssue.MessageMarkdown, @@ -81,6 +82,8 @@ public static void Check( /// null if the issue is not expected to be related to a file or specific column. /// Expected end of column range. /// null if the issue is not expected to be related to a file, specific column or range of columns. + /// Expected file link. + /// null if the issue is not expected to have a file link. /// Expected message in plain text format. /// Expected message in HTML format. /// Expected message in Markdown format. @@ -105,6 +108,7 @@ public static void Check( int? endLine, int? column, int? endColumn, + Uri fileLink, string messageText, string messageHtml, string messageMarkdown, @@ -215,6 +219,12 @@ public static void Check( $"Expected issue.EndColumn to be '{endColumn}' but was '{issue.EndColumn}'."); } + if (issue.FileLink?.ToString() != fileLink?.ToString()) + { + throw new Exception( + $"Expected issue.FileLink to be '{fileLink}' but was '{issue.FileLink}'."); + } + if (issue.MessageText != messageText) { throw new Exception( diff --git a/src/Cake.Issues.Tests/BaseMultiFormatIssueProviderTests.cs b/src/Cake.Issues.Tests/BaseMultiFormatIssueProviderTests.cs index f446e83d8..af78a89b0 100644 --- a/src/Cake.Issues.Tests/BaseMultiFormatIssueProviderTests.cs +++ b/src/Cake.Issues.Tests/BaseMultiFormatIssueProviderTests.cs @@ -110,7 +110,7 @@ public void Should_Read_Issues_From_Format() "Foo".ToByteArray(), format); var provider = new FakeMultiFormatIssueProvider(log, settings); - provider.Initialize(new RepositorySettings(@"c:\repo")); + provider.Initialize(new ReadIssuesSettings(@"c:\repo")); // When var result = provider.ReadIssues(); diff --git a/src/Cake.Issues.Tests/IIssueComparerTests.cs b/src/Cake.Issues.Tests/IIssueComparerTests.cs index 1f76e7eea..ab0f7ed2c 100644 --- a/src/Cake.Issues.Tests/IIssueComparerTests.cs +++ b/src/Cake.Issues.Tests/IIssueComparerTests.cs @@ -155,6 +155,41 @@ public void Should_Return_False_If_Column_Is_Different(int? column1, int? column CompareIssues(issue1, issue2, false); } + [Theory] + [InlineData("http://foo", "http://bar")] + [InlineData("http://foo", null)] + [InlineData(null, "http://foo")] + public void Should_Return_False_If_FileLink_Is_Different(string fileLink1, string fileLink2) + { + // Given + var issueBuilder = + IssueBuilder + .NewIssue("message", "providerType", "providerName"); + if (!string.IsNullOrEmpty(fileLink1)) + { + issueBuilder = + issueBuilder + .WithFileLink(new Uri(fileLink1)); + } + + var issue1 = issueBuilder.Create(); + + issueBuilder = + IssueBuilder + .NewIssue("message", "providerType", "providerName"); + if (!string.IsNullOrEmpty(fileLink2)) + { + issueBuilder = + issueBuilder + .WithFileLink(new Uri(fileLink2)); + } + + var issue2 = issueBuilder.Create(); + + // When / Then + CompareIssues(issue1, issue2, false); + } + [Fact] public void Should_Return_False_If_MessageText_Is_Different() { @@ -532,6 +567,41 @@ public void Should_Return_True_If_Column_Is_Same(int? column1, int? column2) CompareIssues(issue1, issue2, true); } + [Theory] + [InlineData("http://foo", "http://foo")] + [InlineData("http://foo", "http://Foo")] + [InlineData(null, null)] + public void Should_Return_True_If_FileLink_Is_Same(string fileLink1, string fileLink2) + { + // Given + var issueBuilder = + IssueBuilder + .NewIssue("message", "providerType", "providerName"); + if (!string.IsNullOrEmpty(fileLink1)) + { + issueBuilder = + issueBuilder + .WithFileLink(new Uri(fileLink1)); + } + + var issue1 = issueBuilder.Create(); + + issueBuilder = + IssueBuilder + .NewIssue("message", "providerType", "providerName"); + if (!string.IsNullOrEmpty(fileLink2)) + { + issueBuilder = + issueBuilder + .WithFileLink(new Uri(fileLink2)); + } + + var issue2 = issueBuilder.Create(); + + // When / Then + CompareIssues(issue1, issue2, true); + } + [Fact] public void Should_Return_True_If_MessageText_Is_Same() { @@ -1322,6 +1392,76 @@ public void Should_Return_True_If_Column_Is_Same(int? column1, int? column2) CompareIssues(issue1, issue2, true); } + [Theory] + [InlineData("http://foo", "http://bar")] + [InlineData("http://foo", null)] + [InlineData(null, "http://foo")] + public void Should_Return_True_If_FileLink_Is_Different(string fileLink1, string fileLink2) + { + // Given + var issueBuilder = + IssueBuilder + .NewIssue("message", "providerType", "providerName"); + if (!string.IsNullOrEmpty(fileLink1)) + { + issueBuilder = + issueBuilder + .WithFileLink(new Uri(fileLink1)); + } + + var issue1 = issueBuilder.Create(); + + issueBuilder = + IssueBuilder + .NewIssue("message", "providerType", "providerName"); + if (!string.IsNullOrEmpty(fileLink2)) + { + issueBuilder = + issueBuilder + .WithFileLink(new Uri(fileLink2)); + } + + var issue2 = issueBuilder.Create(); + + // When / Then + CompareIssues(issue1, issue2, true); + } + + [Theory] + [InlineData("http://foo", "http://foo")] + [InlineData("http://foo", "http://Foo")] + [InlineData(null, null)] + public void Should_Return_True_If_FileLink_Is_Same(string fileLink1, string fileLink2) + { + // Given + var issueBuilder = + IssueBuilder + .NewIssue("message", "providerType", "providerName"); + if (!string.IsNullOrEmpty(fileLink1)) + { + issueBuilder = + issueBuilder + .WithFileLink(new Uri(fileLink1)); + } + + var issue1 = issueBuilder.Create(); + + issueBuilder = + IssueBuilder + .NewIssue("message", "providerType", "providerName"); + if (!string.IsNullOrEmpty(fileLink2)) + { + issueBuilder = + issueBuilder + .WithFileLink(new Uri(fileLink2)); + } + + var issue2 = issueBuilder.Create(); + + // When / Then + CompareIssues(issue1, issue2, true); + } + [Fact] public void Should_Return_True_If_MessageText_Is_Same() { diff --git a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs index fc1193e48..5cc79e071 100644 --- a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs +++ b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs @@ -311,6 +311,7 @@ public void Should_Throw_If_Issue_Is_Null() [InlineData("foo {EndLine} bar", "foo 420 bar")] [InlineData("foo {Column} bar", "foo 23 bar")] [InlineData("foo {EndColumn} bar", "foo 230 bar")] + [InlineData("foo {FileLink} bar", "foo https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12 bar")] [InlineData("foo {Rule} bar", "foo Rule Foo bar")] [InlineData("foo {RuleUrl} bar", "foo https://google.com/ bar")] [InlineData("foo {MessageText} bar", "foo MessageText Foo bar")] @@ -327,6 +328,7 @@ public void Should_Replace_Tokens(string pattern, string expectedResult) .WithMessageInMarkdownFormat("MessageMarkdown Foo") .InFile(@"src/Cake.Issues/foo.cs", 42, 420, 23, 230) .InProject(@"src/Cake.Issues/Cake.Issues.csproj", "Cake.Issues") + .WithFileLink(new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12")) .OfRule("Rule Foo", new Uri("https://google.com")) .WithPriority(IssuePriority.Error) .Create(); diff --git a/src/Cake.Issues.Tests/IssueBuilderTests.cs b/src/Cake.Issues.Tests/IssueBuilderTests.cs index d5d36a99d..8ac9eec94 100644 --- a/src/Cake.Issues.Tests/IssueBuilderTests.cs +++ b/src/Cake.Issues.Tests/IssueBuilderTests.cs @@ -1604,6 +1604,38 @@ public void Should_Set_EndColumn(int endColumn) } } + public sealed class TheWithFileLinkMethod + { + [Fact] + public void Should_Throw_If_FileLink_Is_Null() + { + // Given + var fixture = new IssueBuilderFixture(); + Uri fileLink = null; + + // When + var result = Record.Exception(() => + fixture.IssueBuilder.WithFileLink(fileLink)); + + // Then + result.IsArgumentNullException("fileLink"); + } + + [Theory] + [InlineData("https://google.com/")] + public void Should_Set_FileLink(string fileLink) + { + // Given + var fixture = new IssueBuilderFixture(); + + // When + var issue = fixture.IssueBuilder.WithFileLink(new Uri(fileLink)).Create(); + + // Then + issue.FileLink.ToString().ShouldBe(fileLink); + } + } + public sealed class TheWithPriorityMethod { [Fact] diff --git a/src/Cake.Issues.Tests/IssueReaderTests.cs b/src/Cake.Issues.Tests/IssueReaderTests.cs index a75cb5093..76f5d0dc4 100644 --- a/src/Cake.Issues.Tests/IssueReaderTests.cs +++ b/src/Cake.Issues.Tests/IssueReaderTests.cs @@ -330,6 +330,59 @@ public void Should_Set_Run_Property() issues.ShouldContain(issue2); issue2.Run.ShouldBe(run); } + + [Fact] + public void Should_Set_FileLink_Property() + { + // Given + var filePath1 = @"src\Cake.Issues.Tests\Foo.cs"; + var line1 = 10; + var issue1 = + IssueBuilder + .NewIssue("Foo", "ProviderTypeFoo", "ProviderNameFoo") + .InFile(filePath1, line1) + .OfRule("Foo") + .WithPriority(IssuePriority.Warning) + .Create(); + var filePath2 = @"src\Cake.Issues.Tests\Bar.cs"; + var line2 = 12; + var issue2 = + IssueBuilder + .NewIssue("Bar", "ProviderTypeBar", "ProviderNameBar") + .InFile(filePath2, line2) + .OfRule("Bar") + .WithPriority(IssuePriority.Warning) + .Create(); + var fixture = new IssuesFixture(); + fixture.IssueProviders.Clear(); + fixture.IssueProviders.Add( + new FakeIssueProvider( + fixture.Log, + new List + { + issue1, + issue2, + })); + var repoUrl = "https://github.com/cake-contrib/Cake.Issues.Website"; + var branch = "develop"; + fixture.Settings.FileLinkSettings = + FileLinkSettings.GitHub( + new System.Uri(repoUrl), + branch, + null); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(2); + issues.ShouldContain(issue1); + issue1.FileLink.ToString() + .ShouldBe($"{repoUrl}/blob/{branch}/{filePath1.Replace(@"\", "/")}#L{line1}"); + issues.ShouldContain(issue2); + issue2.FileLink.ToString() + .ShouldBe($"{repoUrl}/blob/{branch}/{filePath2.Replace(@"\", "/")}#L{line2}"); + } } } } \ No newline at end of file diff --git a/src/Cake.Issues.Tests/IssueTests.cs b/src/Cake.Issues.Tests/IssueTests.cs index ee166c372..5286a4aeb 100644 --- a/src/Cake.Issues.Tests/IssueTests.cs +++ b/src/Cake.Issues.Tests/IssueTests.cs @@ -23,6 +23,7 @@ public void Should_Throw_If_Identifier_Is_Null() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -45,6 +46,7 @@ public void Should_Throw_If_Identifier_Is_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -72,6 +74,7 @@ public void Should_Throw_If_Identifier_Is_Empty() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -94,6 +97,7 @@ public void Should_Throw_If_Identifier_Is_Empty() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -121,6 +125,7 @@ public void Should_Throw_If_Identifier_Is_WhiteSpace() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -143,6 +148,7 @@ public void Should_Throw_If_Identifier_Is_WhiteSpace() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -170,6 +176,7 @@ public void Should_Set_Identifier(string identifier) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -192,6 +199,7 @@ public void Should_Set_Identifier(string identifier) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -222,6 +230,7 @@ public void Should_Throw_If_Project_Path_Is_Invalid(string projectPath) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -244,6 +253,7 @@ public void Should_Throw_If_Project_Path_Is_Invalid(string projectPath) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -273,6 +283,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string projectPath) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -295,6 +306,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string projectPath) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -322,6 +334,7 @@ public void Should_Handle_Project_Paths_Which_Are_Null() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -344,6 +357,7 @@ public void Should_Handle_Project_Paths_Which_Are_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -371,6 +385,7 @@ public void Should_Handle_Project_Paths_Which_Are_Empty() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -393,6 +408,7 @@ public void Should_Handle_Project_Paths_Which_Are_Empty() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -420,6 +436,7 @@ public void Should_Handle_Project_Paths_Which_Are_WhiteSpace() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -442,6 +459,7 @@ public void Should_Handle_Project_Paths_Which_Are_WhiteSpace() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -469,6 +487,7 @@ public void Should_Set_ProjectFileRelativePath(string projectPath) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -491,6 +510,7 @@ public void Should_Set_ProjectFileRelativePath(string projectPath) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -521,6 +541,7 @@ public void Should_Handle_Projects_Which_Are_Null() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -543,6 +564,7 @@ public void Should_Handle_Projects_Which_Are_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -570,6 +592,7 @@ public void Should_Handle_Projects_Which_Are_Empty() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -592,6 +615,7 @@ public void Should_Handle_Projects_Which_Are_Empty() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -619,6 +643,7 @@ public void Should_Handle_Projects_Which_Are_WhiteSpace() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -641,6 +666,7 @@ public void Should_Handle_Projects_Which_Are_WhiteSpace() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -668,6 +694,7 @@ public void Should_Set_ProjectName(string projectName) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -690,6 +717,7 @@ public void Should_Set_ProjectName(string projectName) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -720,6 +748,7 @@ public void Should_Throw_If_File_Path_Is_Invalid(string filePath) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -742,6 +771,7 @@ public void Should_Throw_If_File_Path_Is_Invalid(string filePath) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -771,6 +801,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string filePath) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -793,6 +824,7 @@ public void Should_Throw_If_File_Path_Is_Absolute(string filePath) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -820,6 +852,7 @@ public void Should_Handle_File_Paths_Which_Are_Null() int? endLine = null; int? column = null; int? endColumn = null; + Uri fileLink = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -842,6 +875,7 @@ public void Should_Handle_File_Paths_Which_Are_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -869,6 +903,7 @@ public void Should_Handle_File_Paths_Which_Are_Empty() int? endLine = null; int? column = null; int? endColumn = null; + Uri fileLink = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -891,6 +926,7 @@ public void Should_Handle_File_Paths_Which_Are_Empty() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -918,6 +954,7 @@ public void Should_Handle_File_Paths_Which_Are_WhiteSpace() int? endLine = null; int? column = null; int? endColumn = null; + Uri fileLink = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -940,6 +977,7 @@ public void Should_Handle_File_Paths_Which_Are_WhiteSpace() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -975,6 +1013,7 @@ public void Should_Set_File_Path(string filePath, string expectedFilePath) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -997,6 +1036,7 @@ public void Should_Set_File_Path(string filePath, string expectedFilePath) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1028,6 +1068,7 @@ public void Should_Throw_If_Line_Is_Negative() int? endLine = null; int? column = null; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1050,6 +1091,7 @@ public void Should_Throw_If_Line_Is_Negative() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1077,6 +1119,7 @@ public void Should_Throw_If_Line_Is_Zero() int? endLine = null; int? column = null; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1099,6 +1142,7 @@ public void Should_Throw_If_Line_Is_Zero() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1126,6 +1170,7 @@ public void Should_Throw_If_Line_Is_Set_But_No_File() int? endLine = null; int? column = null; int? endColumn = null; + Uri fileLink = null; var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1148,6 +1193,7 @@ public void Should_Throw_If_Line_Is_Set_But_No_File() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1175,6 +1221,7 @@ public void Should_Handle_Line_Which_Is_Null() int? endLine = null; int? column = null; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1197,6 +1244,7 @@ public void Should_Handle_Line_Which_Is_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1225,6 +1273,7 @@ public void Should_Set_Line(int line) int? endLine = null; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1247,6 +1296,7 @@ public void Should_Set_Line(int line) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1277,6 +1327,7 @@ public void Should_Throw_If_EndLine_Is_Negative() var endLine = -1; int? column = null; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1299,6 +1350,7 @@ public void Should_Throw_If_EndLine_Is_Negative() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1326,6 +1378,7 @@ public void Should_Throw_If_EndLine_Is_Zero() var endLine = 0; int? column = null; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1348,6 +1401,7 @@ public void Should_Throw_If_EndLine_Is_Zero() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1375,6 +1429,7 @@ public void Should_Throw_If_EndLine_Is_Set_But_No_Line() var endLine = 12; int? column = null; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1397,6 +1452,7 @@ public void Should_Throw_If_EndLine_Is_Set_But_No_Line() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1424,6 +1480,7 @@ public void Should_Throw_If_EndLine_Is_Smaller_Line() var endLine = 12; int? column = null; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1446,6 +1503,7 @@ public void Should_Throw_If_EndLine_Is_Smaller_Line() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1473,6 +1531,7 @@ public void Should_Handle_EndLine_Which_Is_Null() int? endLine = null; int? column = null; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1495,6 +1554,7 @@ public void Should_Handle_EndLine_Which_Is_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1522,6 +1582,7 @@ public void Should_Handle_EndLine_Which_Is_Equals_Line() var endLine = 10; int? column = null; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1544,6 +1605,7 @@ public void Should_Handle_EndLine_Which_Is_Equals_Line() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1572,6 +1634,7 @@ public void Should_Set_EndLine(int endLine) var line = 1; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1594,6 +1657,7 @@ public void Should_Set_EndLine(int endLine) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1624,6 +1688,7 @@ public void Should_Throw_If_Column_Is_Negative() var endLine = 12; var column = -1; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1646,6 +1711,7 @@ public void Should_Throw_If_Column_Is_Negative() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1673,6 +1739,7 @@ public void Should_Throw_If_Column_Is_Zero() var endLine = 12; var column = 0; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1695,6 +1762,7 @@ public void Should_Throw_If_Column_Is_Zero() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1722,6 +1790,7 @@ public void Should_Throw_If_Column_Is_Set_But_No_Line() int? endLine = null; var column = 50; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1744,6 +1813,7 @@ public void Should_Throw_If_Column_Is_Set_But_No_Line() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1771,6 +1841,7 @@ public void Should_Handle_Column_Which_Is_Null() var endLine = 12; int? column = null; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1793,6 +1864,7 @@ public void Should_Handle_Column_Which_Is_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1822,6 +1894,7 @@ public void Should_Set_Column(int? column) var line = 10; var endLine = 12; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1844,6 +1917,7 @@ public void Should_Set_Column(int? column) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1874,6 +1948,7 @@ public void Should_Throw_If_EndColumn_Is_Negative() var endLine = 12; var column = 50; var endColumn = -1; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1896,6 +1971,7 @@ public void Should_Throw_If_EndColumn_Is_Negative() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1923,6 +1999,7 @@ public void Should_Throw_If_EndColumn_Is_Zero() var endLine = 12; var column = 50; var endColumn = 0; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1945,6 +2022,7 @@ public void Should_Throw_If_EndColumn_Is_Zero() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -1972,6 +2050,7 @@ public void Should_Throw_If_EndColumn_Is_Set_But_No_Column() var endLine = 12; int? column = null; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -1994,6 +2073,7 @@ public void Should_Throw_If_EndColumn_Is_Set_But_No_Column() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2021,6 +2101,7 @@ public void Should_Throw_If_EndColumn_Is_Smaller_Column() var endLine = 12; var column = 50; var endColumn = 5; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2043,6 +2124,7 @@ public void Should_Throw_If_EndColumn_Is_Smaller_Column() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2070,6 +2152,7 @@ public void Should_Handle_EndColumn_Which_Is_Null() var endLine = 12; int? column = null; int? endColumn = null; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2092,6 +2175,7 @@ public void Should_Handle_EndColumn_Which_Is_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2119,6 +2203,7 @@ public void Should_Handle_EndColumn_Which_Is_Equals_Column() var endLine = 12; var column = 50; var endColumn = 50; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2141,6 +2226,7 @@ public void Should_Handle_EndColumn_Which_Is_Equals_Column() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2170,6 +2256,7 @@ public void Should_Set_EndColumn(int? endColumn) var line = 10; var endLine = 12; var column = 1; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2192,6 +2279,7 @@ public void Should_Set_EndColumn(int? endColumn) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2208,6 +2296,111 @@ public void Should_Set_EndColumn(int? endColumn) } } + public sealed class TheFileLinkArgument + { + [Fact] + public void Should_Set_FileLink() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + var column = 50; + var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var issue = + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + fileLink, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName); + + // Then + issue.FileLink.ShouldBe(fileLink); + } + + [Fact] + public void Should_Set_FileLink_If_Null() + { + // Given + var identifier = "identifier"; + var projectPath = @"src\foo.csproj"; + var projectName = "foo"; + var filePath = @"src\foo.cs"; + var line = 10; + var endLine = 12; + var column = 50; + var endColumn = 55; + Uri fileLink = null; + var messageText = "MessageText"; + var messageHtml = "MessageHtml"; + var messageMarkdown = "MessageMarkdown"; + var priority = 1; + var priorityName = "Warning"; + var rule = "Rule"; + var ruleUri = new Uri("https://google.com"); + var providerType = "ProviderType"; + var providerName = "ProviderName"; + var run = "Run"; + + // When + var issue = + new Issue( + identifier, + projectPath, + projectName, + filePath, + line, + endLine, + column, + endColumn, + fileLink, + messageText, + messageHtml, + messageMarkdown, + priority, + priorityName, + rule, + ruleUri, + run, + providerType, + providerName); + + // Then + issue.FileLink.ShouldBe(fileLink); + } + } + public sealed class TheMessageTextArgument { [Fact] @@ -2222,6 +2415,7 @@ public void Should_Throw_If_MessageText_Is_Null() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); string messageText = null; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2244,6 +2438,7 @@ public void Should_Throw_If_MessageText_Is_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2271,6 +2466,7 @@ public void Should_Throw_If_MessageText_Is_Empty() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = string.Empty; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2293,6 +2489,7 @@ public void Should_Throw_If_MessageText_Is_Empty() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2320,6 +2517,7 @@ public void Should_Throw_If_MessageText_Is_WhiteSpace() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = " "; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2342,6 +2540,7 @@ public void Should_Throw_If_MessageText_Is_WhiteSpace() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2370,6 +2569,7 @@ public void Should_Set_MessageText(string messageText) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; var priority = 1; @@ -2391,6 +2591,7 @@ public void Should_Set_MessageText(string messageText) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2425,6 +2626,7 @@ public void Should_Set_MessageHtml(string messageHtml) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageMarkdown = "MessageMarkdown"; var priority = 1; @@ -2446,6 +2648,7 @@ public void Should_Set_MessageHtml(string messageHtml) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2480,6 +2683,7 @@ public void Should_Set_MessageHtml(string messageMarkdown) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var priority = 1; @@ -2501,6 +2705,7 @@ public void Should_Set_MessageHtml(string messageMarkdown) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2537,6 +2742,7 @@ public void Should_Set_Priority(int? priority) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2558,6 +2764,7 @@ public void Should_Set_Priority(int? priority) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2588,6 +2795,7 @@ public void Should_Handle_PriorityNames_Which_Are_Null() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2610,6 +2818,7 @@ public void Should_Handle_PriorityNames_Which_Are_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2637,6 +2846,7 @@ public void Should_Handle_PriorityNames_Which_Are_Empty() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2659,6 +2869,7 @@ public void Should_Handle_PriorityNames_Which_Are_Empty() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2686,6 +2897,7 @@ public void Should_Handle_PriorityNames_Which_Are_WhiteSpace() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2708,6 +2920,7 @@ public void Should_Handle_PriorityNames_Which_Are_WhiteSpace() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2736,6 +2949,7 @@ public void Should_Set_Priority_Name(string priorityName) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2757,6 +2971,7 @@ public void Should_Set_Priority_Name(string priorityName) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2790,6 +3005,7 @@ public void Should_Set_Rule(string rule) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2811,6 +3027,7 @@ public void Should_Set_Rule(string rule) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2841,6 +3058,7 @@ public void Should_Set_Rule_Url() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2863,6 +3081,7 @@ public void Should_Set_Rule_Url() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2890,6 +3109,7 @@ public void Should_Set_Rule_Url_If_Null() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2912,6 +3132,7 @@ public void Should_Set_Rule_Url_If_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2945,6 +3166,7 @@ public void Should_Set_Run(string run) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -2966,6 +3188,7 @@ public void Should_Set_Run(string run) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -2996,6 +3219,7 @@ public void Should_Throw_If_Provider_Type_Is_Null() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -3018,6 +3242,7 @@ public void Should_Throw_If_Provider_Type_Is_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -3045,6 +3270,7 @@ public void Should_Throw_If_Provider_Type_Is_Empty() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -3067,6 +3293,7 @@ public void Should_Throw_If_Provider_Type_Is_Empty() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -3094,6 +3321,7 @@ public void Should_Throw_If_Provider_Type_Is_WhiteSpace() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -3116,6 +3344,7 @@ public void Should_Throw_If_Provider_Type_Is_WhiteSpace() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -3144,6 +3373,7 @@ public void Should_Set_ProviderType(string providerType) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -3165,6 +3395,7 @@ public void Should_Set_ProviderType(string providerType) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -3195,6 +3426,7 @@ public void Should_Throw_If_Provider_Name_Is_Null() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -3217,6 +3449,7 @@ public void Should_Throw_If_Provider_Name_Is_Null() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -3244,6 +3477,7 @@ public void Should_Throw_If_Provider_Name_Is_Empty() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -3266,6 +3500,7 @@ public void Should_Throw_If_Provider_Name_Is_Empty() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -3293,6 +3528,7 @@ public void Should_Throw_If_Provider_Name_Is_WhiteSpace() var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -3315,6 +3551,7 @@ public void Should_Throw_If_Provider_Name_Is_WhiteSpace() endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, @@ -3343,6 +3580,7 @@ public void Should_Set_ProviderName(string providerName) var endLine = 12; var column = 50; var endColumn = 55; + var fileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); var messageText = "MessageText"; var messageHtml = "MessageHtml"; var messageMarkdown = "MessageMarkdown"; @@ -3364,6 +3602,7 @@ public void Should_Set_ProviderName(string providerName) endLine, column, endColumn, + fileLink, messageText, messageHtml, messageMarkdown, diff --git a/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs b/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs index 634d01649..244117bb0 100644 --- a/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs +++ b/src/Cake.Issues.Tests/Serialization/IssueSerializationExtensionsTests.cs @@ -274,6 +274,24 @@ public void Should_Give_Correct_Result_For_EndColumn_After_Roundtrip() result.EndColumn.ShouldBe(endColumn); } + [Fact] + public void Should_Give_Correct_Result_For_FileLink_After_Roundtrip() + { + // Given + var fileLink = "https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"; + var issue = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .WithFileLink(new Uri(fileLink)) + .Create(); + + // When + var result = issue.SerializeToJsonString().DeserializeToIssue(); + + // Then + result.FileLink.ToString().ShouldBe(fileLink); + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { @@ -746,6 +764,34 @@ public void Should_Give_Correct_Result_For_EndColumn_After_Roundtrip() result.Last().EndColumn.ShouldBe(endColumn2); } + [Fact] + public void Should_Give_Correct_Result_For_FileLink_After_Roundtrip() + { + // Given + var fileLink1 = "https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"; + var fileLink2 = "https://github.com/myorg/myrepo/blob/develop/src/bar.cs#L23-L42"; + var issues = + new List + { + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .WithFileLink(new Uri(fileLink1)) + .Create(), + IssueBuilder + .NewIssue("message2", "providerType2", "providerName2") + .WithFileLink(new Uri(fileLink2)) + .Create(), + }; + + // When + var result = issues.SerializeToJsonString().DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().FileLink.ToString().ShouldBe(fileLink1); + result.Last().FileLink.ToString().ShouldBe(fileLink2); + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { @@ -1308,6 +1354,36 @@ public void Should_Give_Correct_Result_For_EndColumn_After_Roundtrip() } } + [Fact] + public void Should_Give_Correct_Result_For_FileLink_After_Roundtrip() + { + // Given + var fileLink = "https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"; + var issue = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .WithFileLink(new Uri(fileLink)) + .Create(); + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issue.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssue(); + + // Then + result.FileLink.ToString().ShouldBe(fileLink); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { @@ -2011,6 +2087,46 @@ public void Should_Give_Correct_Result_For_EndColumn_After_Roundtrip() } } + [Fact] + public void Should_Give_Correct_Result_For_FileLink_After_Roundtrip() + { + // Given + var fileLink1 = "https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"; + var fileLink2 = "https://github.com/myorg/myrepo/blob/develop/src/bar.cs#L23-L42"; + var issues = + new List + { + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .WithFileLink(new Uri(fileLink1)) + .Create(), + IssueBuilder + .NewIssue("message2", "providerType2", "providerName2") + .WithFileLink(new Uri(fileLink2)) + .Create(), + }; + var filePath = new FilePath(System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".json"); + + try + { + // When + issues.SerializeToJsonFile(filePath); + var result = filePath.DeserializeToIssues(); + + // Then + result.Count().ShouldBe(2); + result.First().FileLink.ToString().ShouldBe(fileLink1); + result.Last().FileLink.ToString().ShouldBe(fileLink2); + } + finally + { + if (System.IO.File.Exists(filePath.FullPath)) + { + System.IO.File.Delete(filePath.FullPath); + } + } + } + [Fact] public void Should_Give_Correct_Result_For_Priority_After_Roundtrip() { diff --git a/src/Cake.Issues.Tests/Testing/BaseConfigurableIssueProviderFixtureTests.cs b/src/Cake.Issues.Tests/Testing/BaseConfigurableIssueProviderFixtureTests.cs index 4d267d669..182507833 100644 --- a/src/Cake.Issues.Tests/Testing/BaseConfigurableIssueProviderFixtureTests.cs +++ b/src/Cake.Issues.Tests/Testing/BaseConfigurableIssueProviderFixtureTests.cs @@ -82,7 +82,7 @@ public void Should_Set_RepositorySettings() var result = new FakeConfigurableIssueProviderFixture("Build.log"); // Then - result.RepositorySettings.ShouldNotBeNull(); + result.ReadIssuesSettings.ShouldNotBeNull(); } [Fact] @@ -136,14 +136,14 @@ public void Should_Throw_If_RepositorySettings_Are_Null() // Given var fixture = new FakeConfigurableIssueProviderFixture("Build.log") { - RepositorySettings = null, + ReadIssuesSettings = null, }; // When var result = Record.Exception(() => fixture.ReadIssues()); // Then - result.IsInvalidOperationException("No repository settings set."); + result.IsInvalidOperationException("No settings for reading issues set."); } [Fact] diff --git a/src/Cake.Issues.Tests/Testing/BaseIssueProviderFixtureTests.cs b/src/Cake.Issues.Tests/Testing/BaseIssueProviderFixtureTests.cs index 5cb0d3268..5aa2d628b 100644 --- a/src/Cake.Issues.Tests/Testing/BaseIssueProviderFixtureTests.cs +++ b/src/Cake.Issues.Tests/Testing/BaseIssueProviderFixtureTests.cs @@ -31,7 +31,7 @@ public void Should_Set_RepositorySettings() var result = new FakeIssueProviderFixture(); // Then - result.RepositorySettings.ShouldNotBeNull(); + result.ReadIssuesSettings.ShouldNotBeNull(); } } @@ -59,14 +59,14 @@ public void Should_Throw_If_RepositorySettings_Are_Null() // Given var fixture = new FakeIssueProviderFixture { - RepositorySettings = null, + ReadIssuesSettings = null, }; // When var result = Record.Exception(() => fixture.ReadIssues()); // Then - result.IsInvalidOperationException("No repository settings set."); + result.IsInvalidOperationException("No settings for reading issues set."); } [Fact] diff --git a/src/Cake.Issues.Tests/Testing/BaseMultiFormatIssueProviderFixtureTests.cs b/src/Cake.Issues.Tests/Testing/BaseMultiFormatIssueProviderFixtureTests.cs index 540dcf176..be71cbfff 100644 --- a/src/Cake.Issues.Tests/Testing/BaseMultiFormatIssueProviderFixtureTests.cs +++ b/src/Cake.Issues.Tests/Testing/BaseMultiFormatIssueProviderFixtureTests.cs @@ -82,7 +82,7 @@ public void Should_Set_RepositorySettings() var result = new FakeMultiFormatIssueProviderFixture("Build.log"); // Then - result.RepositorySettings.ShouldNotBeNull(); + result.ReadIssuesSettings.ShouldNotBeNull(); } [Fact] @@ -136,14 +136,14 @@ public void Should_Throw_If_RepositorySettings_Are_Null() // Given var fixture = new FakeMultiFormatIssueProviderFixture("Build.log") { - RepositorySettings = null, + ReadIssuesSettings = null, }; // When var result = Record.Exception(() => fixture.ReadIssues()); // Then - result.IsInvalidOperationException("No repository settings set."); + result.IsInvalidOperationException("No settings for reading issues set."); } [Fact] diff --git a/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs b/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs index 9e107eab3..09ba57b92 100644 --- a/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs +++ b/src/Cake.Issues.Tests/Testing/IssueCheckerFixture.cs @@ -23,6 +23,7 @@ public IssueCheckerFixture(string identifier, string messageText, string provide this.EndLine = 420; this.Column = 23; this.EndColumn = 230; + this.FileLink = new Uri("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12"); this.MessageText = messageText; this.MessageHtml = "messageHtml"; this.MessageMarkdown = "messageMarkdown"; @@ -37,6 +38,7 @@ public IssueCheckerFixture(string identifier, string messageText, string provide .WithMessageInMarkdownFormat(this.MessageMarkdown) .InProject(this.ProjectFileRelativePath, this.ProjectName) .InFile(this.AffectedFileRelativePath, this.Line, this.EndLine, this.Column, this.EndColumn) + .WithFileLink(this.FileLink) .OfRule(this.Rule, this.RuleUrl) .WithPriority(this.Priority, this.PriorityName); @@ -68,6 +70,8 @@ public IssueCheckerFixture(string identifier, string messageText, string provide public int EndColumn { get; private set; } + public Uri FileLink { get; private set; } + public string MessageText { get; private set; } public string MessageHtml { get; private set; } diff --git a/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs b/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs index c95545a63..d593d31eb 100644 --- a/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs +++ b/src/Cake.Issues.Tests/Testing/IssueCheckerTests.cs @@ -153,6 +153,7 @@ public void Should_Throw_If_Issue_Is_Null() fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -185,6 +186,7 @@ public void Should_Not_Throw_If_All_Values_Are_The_Same() fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -221,6 +223,7 @@ public void Should_Throw_If_ProviderType_Is_Different(string expectedValue, stri fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -259,6 +262,7 @@ public void Should_Throw_If_ProviderName_Is_Different(string expectedValue, stri fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -301,6 +305,7 @@ public void Should_Throw_If_Run_Is_Different(string expectedValue, string actual fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -339,6 +344,7 @@ public void Should_Throw_If_Identifier_Is_Different(string expectedValue, string fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -378,6 +384,7 @@ public void Should_Throw_If_ProjectFileRelativePath_Is_Different(string expected fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -420,6 +427,7 @@ public void Should_Throw_If_ProjectName_Is_Different(string expectedValue, strin fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -459,6 +467,7 @@ public void Should_Throw_If_AffectedFileRelativePath_Is_Different(string expecte fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -500,6 +509,7 @@ public void Should_Throw_If_Line_Is_Different(int? expectedValue, int? actualVal null, null, null, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -541,6 +551,7 @@ public void Should_Throw_If_EndLine_Is_Different(int? expectedValue, int? actual expectedValue, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -582,6 +593,7 @@ public void Should_Throw_If_Column_Is_Different(int? expectedValue, int? actualV fixture.EndLine, expectedValue, null, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -623,6 +635,7 @@ public void Should_Throw_If_EndColumn_Is_Different(int? expectedValue, int? actu fixture.EndLine, fixture.Column, expectedValue, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -636,6 +649,47 @@ public void Should_Throw_If_EndColumn_Is_Different(int? expectedValue, int? actu result.Message.ShouldStartWith("Expected issue.EndColumn"); } + [Theory] + [InlineData("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12", "https://github.com/foo/bar/blob/develop/src/bar.cs")] + [InlineData("https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L12", "https://github.com/myorg/myrepo/blob/develop/src/foo.cs#L10-L13")] + public void Should_Throw_If_FileLink_Is_Different(string expectedValue, string actualValue) + { + // Given + var fixture = new IssueCheckerFixture(); + var issue = + fixture.IssueBuilder + .WithFileLink(new Uri(actualValue)) + .Create(); + + // When + var result = Record.Exception(() => + IssueChecker.Check( + issue, + fixture.ProviderType, + fixture.ProviderName, + fixture.Run, + fixture.Identifier, + fixture.ProjectFileRelativePath, + fixture.ProjectName, + fixture.AffectedFileRelativePath, + fixture.Line, + fixture.EndLine, + fixture.Column, + fixture.EndColumn, + new Uri(expectedValue), + fixture.MessageText, + fixture.MessageHtml, + fixture.MessageMarkdown, + fixture.Priority, + fixture.PriorityName, + fixture.Rule, + fixture.RuleUrl)); + + // Then + result.ShouldBeOfType(); + result.Message.ShouldStartWith("Expected issue.FileLink"); + } + [Theory] [InlineData("Message", "Foo")] [InlineData(null, "Foo")] @@ -661,6 +715,7 @@ public void Should_Throw_If_MessageText_Is_Different(string expectedValue, strin fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, expectedValue, fixture.MessageHtml, fixture.MessageMarkdown, @@ -703,6 +758,7 @@ public void Should_Throw_If_MessageHtml_Is_Different(string expectedValue, strin fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, expectedValue, fixture.MessageMarkdown, @@ -745,6 +801,7 @@ public void Should_Throw_If_MessageMarkdown_Is_Different(string expectedValue, s fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, expectedValue, @@ -784,6 +841,7 @@ public void Should_Throw_If_Priority_Is_Different(IssuePriority expectedValue, I fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -826,6 +884,7 @@ public void Should_Throw_If_PriorityName_Is_Different(string expectedValue, stri fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -868,6 +927,7 @@ public void Should_Throw_If_Rule_Is_Different(string expectedValue, string actua fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, @@ -907,6 +967,7 @@ public void Should_Throw_If_RuleUrl_Is_Different(string expectedValue, string ac fixture.EndLine, fixture.Column, fixture.EndColumn, + fixture.FileLink, fixture.MessageText, fixture.MessageHtml, fixture.MessageMarkdown, diff --git a/src/Cake.Issues/BaseIssueProvider.cs b/src/Cake.Issues/BaseIssueProvider.cs index 3021b9fd9..b270effe7 100644 --- a/src/Cake.Issues/BaseIssueProvider.cs +++ b/src/Cake.Issues/BaseIssueProvider.cs @@ -6,7 +6,7 @@ /// /// Base class for all issue provider implementations. /// - public abstract class BaseIssueProvider : BaseIssueComponent, IIssueProvider + public abstract class BaseIssueProvider : BaseIssueComponent, IIssueProvider { /// /// Initializes a new instance of the class. @@ -25,14 +25,15 @@ public IEnumerable ReadIssues() { this.AssertInitialized(); - return this.InternalReadIssues(); + return this.InternalReadIssues(this.Settings.FileLinkSettings); } /// /// Gets all issues. /// Compared to it is safe to access Settings from this method. /// + /// Settings which can be used for resolving links to source files. /// List of issues. - protected abstract IEnumerable InternalReadIssues(); + protected abstract IEnumerable InternalReadIssues(FileLinkSettings fileLinkSettings); } } diff --git a/src/Cake.Issues/BaseMultiFormatIssueProvider.cs b/src/Cake.Issues/BaseMultiFormatIssueProvider.cs index 92ebb7042..11f327955 100644 --- a/src/Cake.Issues/BaseMultiFormatIssueProvider.cs +++ b/src/Cake.Issues/BaseMultiFormatIssueProvider.cs @@ -23,7 +23,7 @@ protected BaseMultiFormatIssueProvider(ICakeLog log, TSettings settings) } /// - protected override IEnumerable InternalReadIssues() + protected override IEnumerable InternalReadIssues(FileLinkSettings fileLinkSettings) { return this.IssueProviderSettings.Format.ReadIssues( diff --git a/src/Cake.Issues/IIssue.cs b/src/Cake.Issues/IIssue.cs index 12c78dee6..a0a32e262 100644 --- a/src/Cake.Issues/IIssue.cs +++ b/src/Cake.Issues/IIssue.cs @@ -58,6 +58,12 @@ public interface IIssue /// int? EndColumn { get; } + /// + /// Gets or sets a link to the position in the file where the issue ocurred. + /// null if was not set while reading issue. + /// + Uri FileLink { get; set; } + /// /// Gets the message of the issue in text format. /// diff --git a/src/Cake.Issues/IIssueComparer.cs b/src/Cake.Issues/IIssueComparer.cs index d12925243..dfb3e251e 100644 --- a/src/Cake.Issues/IIssueComparer.cs +++ b/src/Cake.Issues/IIssueComparer.cs @@ -47,6 +47,9 @@ public IIssueComparer() /// /// /// + /// + /// + /// /// /// public IIssueComparer(bool compareOnlyPersistentProperties) @@ -76,6 +79,7 @@ public bool Equals(IIssue x, IIssue y) (this.compareOnlyPersistentProperties || x.EndLine == y.EndLine) && (this.compareOnlyPersistentProperties || x.Column == y.Column) && (this.compareOnlyPersistentProperties || x.EndColumn == y.EndColumn) && + (this.compareOnlyPersistentProperties || x.FileLink == y.FileLink) && (x.MessageText == y.MessageText) && (x.MessageHtml == y.MessageHtml) && (x.MessageMarkdown == y.MessageMarkdown) && @@ -125,6 +129,7 @@ public int GetHashCode(IIssue obj) obj.EndLine, obj.Column, obj.EndColumn, + obj.FileLink, obj.MessageText, obj.MessageHtml, obj.MessageMarkdown, diff --git a/src/Cake.Issues/IIssueExtensions.cs b/src/Cake.Issues/IIssueExtensions.cs index bddc2a009..a846ec126 100644 --- a/src/Cake.Issues/IIssueExtensions.cs +++ b/src/Cake.Issues/IIssueExtensions.cs @@ -160,6 +160,10 @@ public static string FileName(this IIssue issue) /// The value of . /// /// + /// {FileLink} + /// The value of . + /// + /// /// {Rule} /// The value of . /// @@ -211,6 +215,7 @@ public static string ReplaceIssuePattern(this string pattern, IIssue issue) .Replace("{EndLine}", issue.EndLine?.ToString()) .Replace("{Column}", issue.Column?.ToString()) .Replace("{EndColumn}", issue.EndColumn?.ToString()) + .Replace("{FileLink}", issue.FileLink?.ToString()) .Replace("{Rule}", issue.Rule) .Replace("{RuleUrl}", issue.RuleUrl?.ToString()) .Replace("{Run}", issue.Run) diff --git a/src/Cake.Issues/IIssueProvider.cs b/src/Cake.Issues/IIssueProvider.cs index 9c71de5dc..63a6ccb62 100644 --- a/src/Cake.Issues/IIssueProvider.cs +++ b/src/Cake.Issues/IIssueProvider.cs @@ -5,7 +5,7 @@ /// /// Interface describing a provider for issues. /// - public interface IIssueProvider : IBaseIssueComponent + public interface IIssueProvider : IBaseIssueComponent { /// /// Gets the human friendly name of the issue provider. diff --git a/src/Cake.Issues/IReadIssuesSettings.cs b/src/Cake.Issues/IReadIssuesSettings.cs index 02153e250..8adb7ba94 100644 --- a/src/Cake.Issues/IReadIssuesSettings.cs +++ b/src/Cake.Issues/IReadIssuesSettings.cs @@ -9,5 +9,10 @@ public interface IReadIssuesSettings : IRepositorySettings /// Gets or sets the name of the run. /// string Run { get; set; } + + /// + /// Gets or sets settings which can be used for resolving links to source files. + /// + FileLinkSettings FileLinkSettings { get; set; } } } diff --git a/src/Cake.Issues/Issue.cs b/src/Cake.Issues/Issue.cs index eba762e75..a7c7f958b 100644 --- a/src/Cake.Issues/Issue.cs +++ b/src/Cake.Issues/Issue.cs @@ -29,6 +29,8 @@ public class Issue : IIssue /// null if the issue affects the whole file or an asssembly. /// The end of the column range in the file where the issues has occurred. /// null if the issue affects the whole file, an asssembly or only a single column. + /// Link to the position in the file where the issue ocurred. + /// null if no link is available. /// The message of the issue in plain text format. /// The message of the issue in Html format. /// The message of the issue in Markdown format. @@ -52,6 +54,7 @@ public Issue( int? endLine, int? column, int? endColumn, + Uri fileLink, string messageText, string messageHtml, string messageMarkdown, @@ -144,6 +147,7 @@ public Issue( this.EndLine = endLine; this.Column = column; this.EndColumn = endColumn; + this.FileLink = fileLink; this.MessageText = messageText; this.MessageHtml = messageHtml; this.MessageMarkdown = messageMarkdown; @@ -180,6 +184,9 @@ public Issue( /// public int? EndColumn { get; } + /// + public Uri FileLink { get; set; } + /// public string MessageText { get; } diff --git a/src/Cake.Issues/IssueBuilder.cs b/src/Cake.Issues/IssueBuilder.cs index ab09271fa..5058deae7 100644 --- a/src/Cake.Issues/IssueBuilder.cs +++ b/src/Cake.Issues/IssueBuilder.cs @@ -20,6 +20,7 @@ public class IssueBuilder private int? endLine; private int? column; private int? endColumn; + private Uri fileLink; private int? priority; private string priorityName; private string rule; @@ -304,6 +305,20 @@ public IssueBuilder InFile(string filePath, int? startLine, int? endLine, int? s return this; } + /// + /// Sets the the link to the position in the file where the issue ocurred. + /// + /// Link to the position in the file where the issue ocurred. + /// Issue Builder instance. + public IssueBuilder WithFileLink(Uri fileLink) + { + fileLink.NotNull(nameof(fileLink)); + + this.fileLink = fileLink; + + return this; + } + /// /// Sets the priority of the issue. /// @@ -389,6 +404,7 @@ public IIssue Create() this.endLine, this.column, this.endColumn, + this.fileLink, this.messageText, this.messageHtml, this.messageMarkdown, diff --git a/src/Cake.Issues/IssuesReader.cs b/src/Cake.Issues/IssuesReader.cs index 349c8f12b..d64e03af9 100644 --- a/src/Cake.Issues/IssuesReader.cs +++ b/src/Cake.Issues/IssuesReader.cs @@ -59,7 +59,15 @@ public IEnumerable ReadIssues() currentIssues.Count, providerName); - currentIssues.ForEach(x => x.Run = this.settings.Run); + currentIssues.ForEach(x => + { + x.Run = this.settings.Run; + + if (this.settings.FileLinkSettings != null) + { + x.FileLink = this.settings.FileLinkSettings.GetFileLink(x); + } + }); issues.AddRange(currentIssues); } diff --git a/src/Cake.Issues/ReadIssuesSettings.cs b/src/Cake.Issues/ReadIssuesSettings.cs index 6f15dc535..1a4c4e6b9 100644 --- a/src/Cake.Issues/ReadIssuesSettings.cs +++ b/src/Cake.Issues/ReadIssuesSettings.cs @@ -18,5 +18,8 @@ public ReadIssuesSettings(DirectoryPath repositoryRoot) /// public string Run { get; set; } + + /// + public FileLinkSettings FileLinkSettings { get; set; } } } diff --git a/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs b/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs index bbc677b5e..01901bdd0 100644 --- a/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs +++ b/src/Cake.Issues/Serialization/IssueSerializationExtensions.cs @@ -88,6 +88,7 @@ internal static SerializableIssueV3 ToSerializableIssue(this IIssue issue) EndLine = issue.EndLine, Column = issue.Column, EndColumn = issue.EndColumn, + FileLink = issue.FileLink?.ToString(), MessageText = issue.MessageText, MessageMarkdown = issue.MessageMarkdown, MessageHtml = issue.MessageHtml, diff --git a/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs b/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs index b5687e06d..24b479dd9 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueExtensions.cs @@ -35,6 +35,7 @@ internal static Issue ToIssue(this SerializableIssue serializableIssue) null, null, null, + null, serializableIssue.Message, null, null, diff --git a/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs b/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs index 8ea394204..3c661919b 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV2Extensions.cs @@ -35,6 +35,7 @@ internal static Issue ToIssue(this SerializableIssueV2 serializableIssue) null, null, null, + null, serializableIssue.MessageText, serializableIssue.MessageHtml, serializableIssue.MessageMarkdown, diff --git a/src/Cake.Issues/Serialization/SerializableIssueV3.cs b/src/Cake.Issues/Serialization/SerializableIssueV3.cs index 9392cd2ce..5c9ac648a 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV3.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV3.cs @@ -52,6 +52,10 @@ public int Version [DataMember] public int? EndColumn { get; set; } + /// + [DataMember] + public string FileLink { get; set; } + /// [DataMember] public string MessageText { get; set; } diff --git a/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs b/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs index f93bd9bea..e0ea7c239 100644 --- a/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs +++ b/src/Cake.Issues/Serialization/SerializableIssueV3Extensions.cs @@ -26,6 +26,12 @@ internal static Issue ToIssue(this SerializableIssueV3 serializableIssue) ruleUrl = new Uri(serializableIssue.RuleUrl); } + Uri fileLink = null; + if (!string.IsNullOrWhiteSpace(serializableIssue.FileLink)) + { + fileLink = new Uri(serializableIssue.FileLink); + } + return new Issue( serializableIssue.Identifier, serializableIssue.ProjectFileRelativePath, @@ -35,6 +41,7 @@ internal static Issue ToIssue(this SerializableIssueV3 serializableIssue) serializableIssue.EndLine, serializableIssue.Column, serializableIssue.EndColumn, + fileLink, serializableIssue.MessageText, serializableIssue.MessageHtml, serializableIssue.MessageMarkdown, From fd2ded60362155f1fd04c76d208893df249c98bb Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Sat, 1 Aug 2020 11:22:51 +0200 Subject: [PATCH 24/31] Don't pass FileLinkSettings to issue provider (#195) File link settings are already available in the settings property. --- src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs | 2 +- src/Cake.Issues.Testing/FakeIssueProvider.cs | 2 +- src/Cake.Issues/BaseIssueProvider.cs | 5 ++--- src/Cake.Issues/BaseMultiFormatIssueProvider.cs | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs b/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs index dde9af839..4330764da 100644 --- a/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs +++ b/src/Cake.Issues.Testing/FakeConfigurableIssueProvider.cs @@ -59,7 +59,7 @@ public FakeConfigurableIssueProvider( public override string ProviderName => "Fake Issue Provider"; /// - protected override IEnumerable InternalReadIssues(FileLinkSettings fileLinkSettings) + protected override IEnumerable InternalReadIssues() { return this.issues; } diff --git a/src/Cake.Issues.Testing/FakeIssueProvider.cs b/src/Cake.Issues.Testing/FakeIssueProvider.cs index 6aefc7f5b..ae83e6481 100644 --- a/src/Cake.Issues.Testing/FakeIssueProvider.cs +++ b/src/Cake.Issues.Testing/FakeIssueProvider.cs @@ -48,7 +48,7 @@ public FakeIssueProvider(ICakeLog log, IEnumerable issues) public override string ProviderName => "Fake Issue Provider"; /// - protected override IEnumerable InternalReadIssues(FileLinkSettings fileLinkSettings) + protected override IEnumerable InternalReadIssues() { return this.issues; } diff --git a/src/Cake.Issues/BaseIssueProvider.cs b/src/Cake.Issues/BaseIssueProvider.cs index b270effe7..af26171bc 100644 --- a/src/Cake.Issues/BaseIssueProvider.cs +++ b/src/Cake.Issues/BaseIssueProvider.cs @@ -25,15 +25,14 @@ public IEnumerable ReadIssues() { this.AssertInitialized(); - return this.InternalReadIssues(this.Settings.FileLinkSettings); + return this.InternalReadIssues(); } /// /// Gets all issues. /// Compared to it is safe to access Settings from this method. /// - /// Settings which can be used for resolving links to source files. /// List of issues. - protected abstract IEnumerable InternalReadIssues(FileLinkSettings fileLinkSettings); + protected abstract IEnumerable InternalReadIssues(); } } diff --git a/src/Cake.Issues/BaseMultiFormatIssueProvider.cs b/src/Cake.Issues/BaseMultiFormatIssueProvider.cs index 11f327955..92ebb7042 100644 --- a/src/Cake.Issues/BaseMultiFormatIssueProvider.cs +++ b/src/Cake.Issues/BaseMultiFormatIssueProvider.cs @@ -23,7 +23,7 @@ protected BaseMultiFormatIssueProvider(ICakeLog log, TSettings settings) } /// - protected override IEnumerable InternalReadIssues(FileLinkSettings fileLinkSettings) + protected override IEnumerable InternalReadIssues() { return this.IssueProviderSettings.Format.ReadIssues( From f0e75367c904089271016c88be22ca91322562d7 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Mon, 3 Aug 2020 22:00:22 +0200 Subject: [PATCH 25/31] Support line ranges and columns in file link settings (#198) --- .../FileLinkSettingsTests.cs | 26 +++++++++---------- src/Cake.Issues.Tests/IssueReaderTests.cs | 7 ++--- src/Cake.Issues/FileLinkSettings.cs | 10 +++++-- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/Cake.Issues.Tests/FileLinkSettingsTests.cs b/src/Cake.Issues.Tests/FileLinkSettingsTests.cs index a2311f657..4702f5ef3 100644 --- a/src/Cake.Issues.Tests/FileLinkSettingsTests.cs +++ b/src/Cake.Issues.Tests/FileLinkSettingsTests.cs @@ -74,12 +74,12 @@ public void Should_Throw_If_Branch_Is_Whitespace() } [Theory] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/{FilePath}#L{Line}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website/", "master", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/{FilePath}#L{Line}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "/foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo/", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo/bar", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/bar/{FilePath}#L{Line}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/{FilePath}#L{Line}-L{EndLine}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website/", "master", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/{FilePath}#L{Line}-L{EndLine}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}-L{EndLine}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "/foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}-L{EndLine}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo/", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}-L{EndLine}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo/bar", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/bar/{FilePath}#L{Line}-L{EndLine}")] public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string branch, string rootPath, string expectedPattern) { // Given @@ -159,13 +159,13 @@ public void Should_Throw_If_Branch_Is_Whitespace() } [Theory] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", null, "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path={FilePath}&version=GBmaster&line={Line}")] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository/", "master", null, "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path={FilePath}&version=GBmaster&line={Line}")] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}")] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "/foo", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}")] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo/", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}")] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo/bar", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/bar/{FilePath}&version=GBmaster&line={Line}")] - [InlineData("https://dev.azure.com/myorganization/_git/myrepo", "master", "foo/bar", "https://dev.azure.com/myorganization/_git/myrepo?path=foo/bar/{FilePath}&version=GBmaster&line={Line}")] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", null, "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path={FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository/", "master", null, "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path={FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "/foo", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo/", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] + [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo/bar", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/bar/{FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] + [InlineData("https://dev.azure.com/myorganization/_git/myrepo", "master", "foo/bar", "https://dev.azure.com/myorganization/_git/myrepo?path=foo/bar/{FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string branch, string rootPath, string expectedPattern) { // Given diff --git a/src/Cake.Issues.Tests/IssueReaderTests.cs b/src/Cake.Issues.Tests/IssueReaderTests.cs index 76f5d0dc4..fcf891b1a 100644 --- a/src/Cake.Issues.Tests/IssueReaderTests.cs +++ b/src/Cake.Issues.Tests/IssueReaderTests.cs @@ -337,10 +337,11 @@ public void Should_Set_FileLink_Property() // Given var filePath1 = @"src\Cake.Issues.Tests\Foo.cs"; var line1 = 10; + var endLine1 = 12; var issue1 = IssueBuilder .NewIssue("Foo", "ProviderTypeFoo", "ProviderNameFoo") - .InFile(filePath1, line1) + .InFile(filePath1, line1, endLine1, 1, 1) .OfRule("Foo") .WithPriority(IssuePriority.Warning) .Create(); @@ -378,10 +379,10 @@ public void Should_Set_FileLink_Property() issues.Count.ShouldBe(2); issues.ShouldContain(issue1); issue1.FileLink.ToString() - .ShouldBe($"{repoUrl}/blob/{branch}/{filePath1.Replace(@"\", "/")}#L{line1}"); + .ShouldBe($"{repoUrl}/blob/{branch}/{filePath1.Replace(@"\", "/")}#L{line1}-L{endLine1}"); issues.ShouldContain(issue2); issue2.FileLink.ToString() - .ShouldBe($"{repoUrl}/blob/{branch}/{filePath2.Replace(@"\", "/")}#L{line2}"); + .ShouldBe($"{repoUrl}/blob/{branch}/{filePath2.Replace(@"\", "/")}#L{line2}-L"); } } } diff --git a/src/Cake.Issues/FileLinkSettings.cs b/src/Cake.Issues/FileLinkSettings.cs index e815f08dc..1efa73d0d 100644 --- a/src/Cake.Issues/FileLinkSettings.cs +++ b/src/Cake.Issues/FileLinkSettings.cs @@ -46,7 +46,7 @@ public static FileLinkSettings GitHub( return new FileLinkSettings( - repositoryUrl.Append("blob", branch, rootPath, "{FilePath}#L{Line}").ToString()); + repositoryUrl.Append("blob", branch, rootPath, "{FilePath}#L{Line}-L{EndLine}").ToString()); } /// @@ -73,7 +73,13 @@ public static FileLinkSettings AzureDevOps( return new FileLinkSettings( - repositoryUrl.ToString().TrimEnd('/') + "?path=" + rootPath + "{FilePath}&version=GB" + branch + "&line={Line}"); + repositoryUrl.ToString().TrimEnd('/') + + "?path=" + rootPath + "{FilePath}" + + "&version=GB" + branch + + "&line={Line}" + + "&lineEnd={EndLine}" + + "&lineStartColumn={Column}" + + "&lineEndColumn={EndColumn}"); } } } From 5658d5dd562c7918505ebe61f2e2c769bb67c2e6 Mon Sep 17 00:00:00 2001 From: Jannik Date: Mon, 3 Aug 2020 22:58:06 +0200 Subject: [PATCH 26/31] Support for CommitId in FileLinkSettings (#196) Co-authored-by: janniksam --- .../FileLinkSettingsTests.cs | 190 ++++++++++++++++-- src/Cake.Issues.Tests/IssueReaderTests.cs | 2 +- src/Cake.Issues/Aliases.FileLinking.cs | 132 ++++++++++-- src/Cake.Issues/FileLinkSettings.cs | 63 +++++- 4 files changed, 354 insertions(+), 33 deletions(-) diff --git a/src/Cake.Issues.Tests/FileLinkSettingsTests.cs b/src/Cake.Issues.Tests/FileLinkSettingsTests.cs index 4702f5ef3..7bb08f178 100644 --- a/src/Cake.Issues.Tests/FileLinkSettingsTests.cs +++ b/src/Cake.Issues.Tests/FileLinkSettingsTests.cs @@ -7,7 +7,7 @@ public sealed class FileLinkSettingsTests { - public sealed class TheGitHubMethod + public sealed class TheGitHubBranchMethod { [Fact] public void Should_Throw_If_RepositoryUrl_Is_Null() @@ -19,7 +19,7 @@ public void Should_Throw_If_RepositoryUrl_Is_Null() // When var result = Record.Exception(() => - FileLinkSettings.GitHub(repositoryUrl, branch, rootPath)); + FileLinkSettings.GitHubBranch(repositoryUrl, branch, rootPath)); // Then result.IsArgumentNullException("repositoryUrl"); @@ -35,7 +35,7 @@ public void Should_Throw_If_Branch_Is_Null() // When var result = Record.Exception(() => - FileLinkSettings.GitHub(repositoryUrl, branch, rootPath)); + FileLinkSettings.GitHubBranch(repositoryUrl, branch, rootPath)); // Then result.IsArgumentNullException("branch"); @@ -51,7 +51,7 @@ public void Should_Throw_If_Branch_Is_Empty() // When var result = Record.Exception(() => - FileLinkSettings.GitHub(repositoryUrl, branch, rootPath)); + FileLinkSettings.GitHubBranch(repositoryUrl, branch, rootPath)); // Then result.IsArgumentOutOfRangeException("branch"); @@ -67,7 +67,7 @@ public void Should_Throw_If_Branch_Is_Whitespace() // When var result = Record.Exception(() => - FileLinkSettings.GitHub(repositoryUrl, branch, rootPath)); + FileLinkSettings.GitHubBranch(repositoryUrl, branch, rootPath)); // Then result.IsArgumentOutOfRangeException("branch"); @@ -85,14 +85,99 @@ public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string bran // Given // When - var result = FileLinkSettings.GitHub(new Uri(repositoryUrl), branch, rootPath); + var result = FileLinkSettings.GitHubBranch(new Uri(repositoryUrl), branch, rootPath); // Then result.FileLinkPattern.ShouldBe(expectedPattern); } } - public sealed class TheAzureDevOpsMethod + public sealed class TheGitHubCommitMethod + { + [Fact] + public void Should_Throw_If_RepositoryUrl_Is_Null() + { + // Given + Uri repositoryUrl = null; + var commitId = "87eaf0a0cf1746179e8714eae4114d10"; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.GitHubCommit(repositoryUrl, commitId, rootPath)); + + // Then + result.IsArgumentNullException("repositoryUrl"); + } + + [Fact] + public void Should_Throw_If_CommitId_Is_Null() + { + // Given + var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); + string commitId = null; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.GitHubCommit(repositoryUrl, commitId, rootPath)); + + // Then + result.IsArgumentNullException("commitId"); + } + + [Fact] + public void Should_Throw_If_CommitId_Is_Empty() + { + // Given + var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); + var commitId = string.Empty; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.GitHubCommit(repositoryUrl, commitId, rootPath)); + + // Then + result.IsArgumentOutOfRangeException("commitId"); + } + + [Fact] + public void Should_Throw_If_CommitId_Is_Whitespace() + { + // Given + var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); + var commitId = " "; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.GitHubCommit(repositoryUrl, commitId, rootPath)); + + // Then + result.IsArgumentOutOfRangeException("commitId"); + } + + [Theory] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "87eaf0a0cf1746179e8714eae4114d10", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/{FilePath}#L{Line}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website/", "87eaf0a0cf1746179e8714eae4114d10", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/{FilePath}#L{Line}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "87eaf0a0cf1746179e8714eae4114d10", "foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/foo/{FilePath}#L{Line}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "87eaf0a0cf1746179e8714eae4114d10", "/foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/foo/{FilePath}#L{Line}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "87eaf0a0cf1746179e8714eae4114d10", "foo/", "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/foo/{FilePath}#L{Line}")] + [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "87eaf0a0cf1746179e8714eae4114d10", "foo/bar", "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/foo/bar/{FilePath}#L{Line}")] + public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string commitId, string rootPath, string expectedPattern) + { + // Given + + // When + var result = FileLinkSettings.GitHubCommit(new Uri(repositoryUrl), commitId, rootPath); + + // Then + result.FileLinkPattern.ShouldBe(expectedPattern); + } + } + + public sealed class TheAzureDevOpsBranchMethod { [Fact] public void Should_Throw_If_RepositoryUrl_Is_Null() @@ -104,7 +189,7 @@ public void Should_Throw_If_RepositoryUrl_Is_Null() // When var result = Record.Exception(() => - FileLinkSettings.AzureDevOps(repositoryUrl, branch, rootPath)); + FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath)); // Then result.IsArgumentNullException("repositoryUrl"); @@ -120,7 +205,7 @@ public void Should_Throw_If_Branch_Is_Null() // When var result = Record.Exception(() => - FileLinkSettings.AzureDevOps(repositoryUrl, branch, rootPath)); + FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath)); // Then result.IsArgumentNullException("branch"); @@ -136,7 +221,7 @@ public void Should_Throw_If_Branch_Is_Empty() // When var result = Record.Exception(() => - FileLinkSettings.AzureDevOps(repositoryUrl, branch, rootPath)); + FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath)); // Then result.IsArgumentOutOfRangeException("branch"); @@ -152,7 +237,7 @@ public void Should_Throw_If_Branch_Is_Whitespace() // When var result = Record.Exception(() => - FileLinkSettings.AzureDevOps(repositoryUrl, branch, rootPath)); + FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath)); // Then result.IsArgumentOutOfRangeException("branch"); @@ -171,7 +256,88 @@ public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string bran // Given // When - var result = FileLinkSettings.AzureDevOps(new Uri(repositoryUrl), branch, rootPath); + var result = FileLinkSettings.AzureDevOpsBranch(new Uri(repositoryUrl), branch, rootPath); + + // Then + result.FileLinkPattern.ShouldBe(expectedPattern); + } + } + + public sealed class TheAzureDevOpsCommitMethod + { + [Fact] + public void Should_Throw_If_RepositoryUrl_Is_Null() + { + // Given + Uri repositoryUrl = null; + var branch = "master"; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath)); + + // Then + result.IsArgumentNullException("repositoryUrl"); + } + + [Fact] + public void Should_Throw_If_CommitId_Is_Null() + { + // Given + var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); + string commitId = null; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.AzureDevOpsCommit(repositoryUrl, commitId, rootPath)); + + // Then + result.IsArgumentNullException("commitId"); + } + + [Fact] + public void Should_Throw_If_CommitId_Is_Empty() + { + // Given + var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); + var commitId = string.Empty; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.AzureDevOpsCommit(repositoryUrl, commitId, rootPath)); + + // Then + result.IsArgumentOutOfRangeException("commitId"); + } + + [Fact] + public void Should_Throw_If_CommitId_Is_Whitespace() + { + // Given + var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); + var commitId = " "; + var rootPath = string.Empty; + + // When + var result = Record.Exception(() => + FileLinkSettings.AzureDevOpsCommit(repositoryUrl, commitId, rootPath)); + + // Then + result.IsArgumentOutOfRangeException("commitId"); + } + + [Theory] + [InlineData("https://dev.azure.com/myorganization/_git/myrepo", "daf015105140e98d6f296e0db2a80d28b84e7f59", null, "https://dev.azure.com/myorganization/_git/myrepo?path={FilePath}&version=GCdaf015105140e98d6f296e0db2a80d28b84e7f59&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] + [InlineData("https://dev.azure.com/myorganization/_git/myrepo", "daf015105140e98d6f296e0db2a80d28b84e7f59", "foo/bar", "https://dev.azure.com/myorganization/_git/myrepo?path=foo/bar/{FilePath}&version=GCdaf015105140e98d6f296e0db2a80d28b84e7f59&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] + public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string commitId, string rootPath, string expectedPattern) + { + // Given + + // When + var result = FileLinkSettings.AzureDevOpsCommit(new Uri(repositoryUrl), commitId, rootPath); // Then result.FileLinkPattern.ShouldBe(expectedPattern); diff --git a/src/Cake.Issues.Tests/IssueReaderTests.cs b/src/Cake.Issues.Tests/IssueReaderTests.cs index fcf891b1a..08a02df78 100644 --- a/src/Cake.Issues.Tests/IssueReaderTests.cs +++ b/src/Cake.Issues.Tests/IssueReaderTests.cs @@ -367,7 +367,7 @@ public void Should_Set_FileLink_Property() var repoUrl = "https://github.com/cake-contrib/Cake.Issues.Website"; var branch = "develop"; fixture.Settings.FileLinkSettings = - FileLinkSettings.GitHub( + FileLinkSettings.GitHubBranch( new System.Uri(repoUrl), branch, null); diff --git a/src/Cake.Issues/Aliases.FileLinking.cs b/src/Cake.Issues/Aliases.FileLinking.cs index 003c8db6e..03127102b 100644 --- a/src/Cake.Issues/Aliases.FileLinking.cs +++ b/src/Cake.Issues/Aliases.FileLinking.cs @@ -10,16 +10,16 @@ public static partial class Aliases { /// - /// Gets an instance of the file link settings for linking files hosted on GitHub. + /// Gets an instance of the file link settings for linking files hosted on GitHub on a specific branch. /// /// The context. /// Full URL of the Git repository, /// eg. https://github.com/cake-contrib/Cake.Issues.Reporting.Generic. - /// Name of the branch. + /// Name of the branch on which the file linking will be based on. /// Settings for linking to files hosted in GitHub. [CakeMethodAlias] [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] - public static FileLinkSettings IssueFileLinkSettingsForGitHub( + public static FileLinkSettings IssueFileLinkSettingsForGitHubBranch( this ICakeContext context, Uri repositoryUrl, string branch) @@ -28,22 +28,23 @@ public static FileLinkSettings IssueFileLinkSettingsForGitHub( repositoryUrl.NotNull(nameof(repositoryUrl)); branch.NotNullOrWhiteSpace(nameof(branch)); - return context.IssueFileLinkSettingsForGitHub(repositoryUrl, branch, null); + return context.IssueFileLinkSettingsForGitHubBranch(repositoryUrl, branch, null); } /// - /// Gets an instance of the file link settings for linking files hosted on GitHub in a sub-folder. + /// Gets an instance of the file link settings for linking files hosted on GitHub + /// in a sub-folder on a specific branch. /// /// The context. /// Full URL of the Git repository, /// eg. https://github.com/cake-contrib/Cake.Issues.Reporting.Generic. - /// Name of the branch. + /// Name of the branch on which the file linking will be based on. /// Root path of the files. /// null or if files are in the root of the repository. /// Settings for linking to files hosted in GitHub. [CakeMethodAlias] [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] - public static FileLinkSettings IssueFileLinkSettingsForGitHub( + public static FileLinkSettings IssueFileLinkSettingsForGitHubBranch( this ICakeContext context, Uri repositoryUrl, string branch, @@ -53,20 +54,69 @@ public static FileLinkSettings IssueFileLinkSettingsForGitHub( repositoryUrl.NotNull(nameof(repositoryUrl)); branch.NotNullOrWhiteSpace(nameof(branch)); - return FileLinkSettings.GitHub(repositoryUrl, branch, rootPath); + return FileLinkSettings.GitHubBranch(repositoryUrl, branch, rootPath); } /// - /// Gets an instance of the file link settings for linking to files hosted in Azure DevOps. + /// Gets an instance of the file link settings for linking files hosted on GitHub fo a specific commit. + /// + /// The context. + /// Full URL of the Git repository, + /// eg. https://github.com/cake-contrib/Cake.Issues.Reporting.Generic. + /// The commit id on which the file linking will be based on. + /// Settings for linking to files hosted in GitHub. + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] + public static FileLinkSettings IssueFileLinkSettingsForGitHubCommit( + this ICakeContext context, + Uri repositoryUrl, + string commitId) + { + context.NotNull(nameof(context)); + repositoryUrl.NotNull(nameof(repositoryUrl)); + commitId.NotNullOrWhiteSpace(nameof(commitId)); + + return context.IssueFileLinkSettingsForGitHubCommit(repositoryUrl, commitId, null); + } + + /// + /// Gets an instance of the file link settings for linking files hosted on GitHub + /// in a sub-folder for a specific commit. + /// + /// The context. + /// Full URL of the Git repository, + /// eg. https://github.com/cake-contrib/Cake.Issues.Reporting.Generic. + /// The commit id on which the file linking will be based on. + /// Root path of the files. + /// null or if files are in the root of the repository. + /// Settings for linking to files hosted in GitHub. + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] + public static FileLinkSettings IssueFileLinkSettingsForGitHubCommit( + this ICakeContext context, + Uri repositoryUrl, + string commitId, + string rootPath) + { + context.NotNull(nameof(context)); + repositoryUrl.NotNull(nameof(repositoryUrl)); + commitId.NotNullOrWhiteSpace(nameof(commitId)); + + return FileLinkSettings.GitHubCommit(repositoryUrl, commitId, rootPath); + } + + /// + /// Gets an instance of the file link settings for linking to files hosted in Azure DevOps + /// on a specific branch. /// /// The context. /// Full URL of the Git repository, /// eg. https://dev.azure.com/myorganization/_git/myrepo. - /// Name of the branch. + /// Name of the branch on which the file linking will be based on. /// Settings for linking files hosted on Azure DevOps or Azure DevOps Server. [CakeMethodAlias] [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] - public static FileLinkSettings IssueFileLinkSettingsForAzureDevOps( + public static FileLinkSettings IssueFileLinkSettingsForAzureDevOpsBranch( this ICakeContext context, Uri repositoryUrl, string branch) @@ -75,22 +125,23 @@ public static FileLinkSettings IssueFileLinkSettingsForAzureDevOps( repositoryUrl.NotNull(nameof(repositoryUrl)); branch.NotNullOrWhiteSpace(nameof(branch)); - return context.IssueFileLinkSettingsForAzureDevOps(repositoryUrl, branch, null); + return context.IssueFileLinkSettingsForAzureDevOpsBranch(repositoryUrl, branch, null); } /// - /// Gets an instance of the file link settings for linking to files hosted in Azure DevOps in a sub-folder. + /// Gets an instance of the file link settings for linking to files hosted in Azure DevOps + /// in a sub-folder on a specific branch. /// /// The context. /// Full URL of the Git repository, /// eg. https://dev.azure.com/myorganization/_git/myrepo. - /// Name of the branch. + /// Name of the branch on which the file linking will be based on. /// Root path of the files. /// null or if files are in the root of the repository. /// Settings for linking files hosted on Azure DevOps. [CakeMethodAlias] [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] - public static FileLinkSettings IssueFileLinkSettingsForAzureDevOps( + public static FileLinkSettings IssueFileLinkSettingsForAzureDevOpsBranch( this ICakeContext context, Uri repositoryUrl, string branch, @@ -100,7 +151,56 @@ public static FileLinkSettings IssueFileLinkSettingsForAzureDevOps( repositoryUrl.NotNull(nameof(repositoryUrl)); branch.NotNullOrWhiteSpace(nameof(branch)); - return FileLinkSettings.AzureDevOps(repositoryUrl, branch, rootPath); + return FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath); + } + + /// + /// Gets an instance of the file link settings for linking to files hosted in Azure DevOps + /// for a specific commit. + /// + /// The context. + /// Full URL of the Git repository, + /// eg. https://dev.azure.com/myorganization/_git/myrepo. + /// The commit id on which the file linking will be based on. + /// Settings for linking files hosted on Azure DevOps or Azure DevOps Server. + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] + public static FileLinkSettings IssueFileLinkSettingsForAzureDevOpsCommit( + this ICakeContext context, + Uri repositoryUrl, + string commitId) + { + context.NotNull(nameof(context)); + repositoryUrl.NotNull(nameof(repositoryUrl)); + commitId.NotNullOrWhiteSpace(nameof(commitId)); + + return context.IssueFileLinkSettingsForAzureDevOpsCommit(repositoryUrl, commitId, null); + } + + /// + /// Gets an instance of the file link settings for linking to files hosted in Azure DevOps + /// in a sub-folder for a specific commit. + /// + /// The context. + /// Full URL of the Git repository, + /// eg. https://dev.azure.com/myorganization/_git/myrepo. + /// The commit id on which the file linking will be based on. + /// Root path of the files. + /// null or if files are in the root of the repository. + /// Settings for linking files hosted on Azure DevOps. + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] + public static FileLinkSettings IssueFileLinkSettingsForAzureDevOpsCommit( + this ICakeContext context, + Uri repositoryUrl, + string commitId, + string rootPath) + { + context.NotNull(nameof(context)); + repositoryUrl.NotNull(nameof(repositoryUrl)); + commitId.NotNullOrWhiteSpace(nameof(commitId)); + + return FileLinkSettings.AzureDevOpsCommit(repositoryUrl, commitId, rootPath); } } } diff --git a/src/Cake.Issues/FileLinkSettings.cs b/src/Cake.Issues/FileLinkSettings.cs index 1efa73d0d..472bd4913 100644 --- a/src/Cake.Issues/FileLinkSettings.cs +++ b/src/Cake.Issues/FileLinkSettings.cs @@ -28,7 +28,7 @@ public FileLinkSettings(string fileLinkPattern) public string FileLinkPattern { get; } /// - /// Returns settings for linking to files hosted in GitHub. + /// Returns settings for linking to files hosted in GitHub on a specific branch. /// /// Full URL of the Git repository, /// eg. https://github.com/cake-contrib/Cake.Issues. @@ -36,7 +36,7 @@ public FileLinkSettings(string fileLinkPattern) /// Root path of the files. /// null or if files are in the root of the repository. /// Settings for linking to files hosted in GitHub. - public static FileLinkSettings GitHub( + public static FileLinkSettings GitHubBranch( Uri repositoryUrl, string branch, string rootPath) @@ -50,7 +50,29 @@ public static FileLinkSettings GitHub( } /// - /// Returns settings for linking to files hosted in Azure DevOps. + /// Returns settings for linking to files hosted in GitHub for a specific commit. + /// + /// Full URL of the Git repository, + /// eg. https://github.com/cake-contrib/Cake.Issues. + /// The commit id on which the file linking will be based on. + /// Root path of the files. + /// null or if files are in the root of the repository. + /// Settings for linking to files hosted in GitHub. + public static FileLinkSettings GitHubCommit( + Uri repositoryUrl, + string commitId, + string rootPath) + { + repositoryUrl.NotNull(nameof(repositoryUrl)); + commitId.NotNullOrWhiteSpace(nameof(commitId)); + + return + new FileLinkSettings( + repositoryUrl.Append("blob", commitId, rootPath, "{FilePath}#L{Line}").ToString()); + } + + /// + /// Returns settings for linking to files hosted in Azure DevOps on a specific branch. /// /// Full URL of the Git repository, /// e.g. https://dev.azure.com/myorganization/_git/myrepo. @@ -58,7 +80,7 @@ public static FileLinkSettings GitHub( /// Root path of the files. /// null or if files are in the root of the repository. /// Settings for linking to files hosted in Azure DevOps. - public static FileLinkSettings AzureDevOps( + public static FileLinkSettings AzureDevOpsBranch( Uri repositoryUrl, string branch, string rootPath) @@ -81,5 +103,38 @@ public static FileLinkSettings AzureDevOps( "&lineStartColumn={Column}" + "&lineEndColumn={EndColumn}"); } + + /// + /// Returns settings for linking to files hosted in Azure DevOps for a specific commit id. + /// + /// Full URL of the Git repository, + /// e.g. https://dev.azure.com/myorganization/_git/myrepo. + /// The commit id on which the file linking will be based on. + /// Root path of the files. + /// null or if files are in the root of the repository. + /// Settings for linking to files hosted in Azure DevOps. + public static FileLinkSettings AzureDevOpsCommit( + Uri repositoryUrl, + string commitId, + string rootPath) + { + repositoryUrl.NotNull(nameof(repositoryUrl)); + commitId.NotNullOrWhiteSpace(nameof(commitId)); + + if (!string.IsNullOrWhiteSpace(rootPath)) + { + rootPath = rootPath.Trim('/') + "/"; + } + + return + new FileLinkSettings( + repositoryUrl.ToString().TrimEnd('/') + + "?path=" + rootPath + "{FilePath}" + + "&version=GC" + commitId + + "&line={Line}" + + "&lineEnd={EndLine}" + + "&lineStartColumn={Column}" + + "&lineEndColumn={EndColumn}"); + } } } From cb35f2cb0d600cfef2c2493eef3736d94f478d0a Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Thu, 6 Aug 2020 19:43:18 +0200 Subject: [PATCH 27/31] Refactor file link settings to allow dynamic created file links (#199) --- .../FileLinkSettingsTests.cs | 307 +------------ ...AzureDevOpsFileLinkSettingsBuilderTests.cs | 411 ++++++++++++++++++ .../FileLinkOptionalSettingsBuilderTests.cs | 98 +++++ .../GitHubFileLinkSettingsBuilderTests.cs | 339 +++++++++++++++ .../FileLinking/IDictionaryExtensionsTests.cs | 55 +++ src/Cake.Issues.Tests/IssueReaderTests.cs | 7 +- src/Cake.Issues/Aliases.FileLinking.cs | 30 +- src/Cake.Issues/FileLinkSettings.cs | 122 +----- src/Cake.Issues/FileLinkSettingsExtensions.cs | 25 -- .../AzureDevOpsFileLinkSettingsBuilder.cs | 97 +++++ .../FileLinkOptionalSettingsBuilder.cs | 53 +++ .../GitHubFileLinkSettingsBuilder.cs | 102 +++++ .../FileLinking/IDictionaryExtensions.cs | 29 ++ src/Cake.Issues/IIssueExtensions.cs | 4 +- 14 files changed, 1254 insertions(+), 425 deletions(-) create mode 100644 src/Cake.Issues.Tests/FileLinking/AzureDevOpsFileLinkSettingsBuilderTests.cs create mode 100644 src/Cake.Issues.Tests/FileLinking/FileLinkOptionalSettingsBuilderTests.cs create mode 100644 src/Cake.Issues.Tests/FileLinking/GitHubFileLinkSettingsBuilderTests.cs create mode 100644 src/Cake.Issues.Tests/FileLinking/IDictionaryExtensionsTests.cs delete mode 100644 src/Cake.Issues/FileLinkSettingsExtensions.cs create mode 100644 src/Cake.Issues/FileLinking/AzureDevOpsFileLinkSettingsBuilder.cs create mode 100644 src/Cake.Issues/FileLinking/FileLinkOptionalSettingsBuilder.cs create mode 100644 src/Cake.Issues/FileLinking/GitHubFileLinkSettingsBuilder.cs create mode 100644 src/Cake.Issues/FileLinking/IDictionaryExtensions.cs diff --git a/src/Cake.Issues.Tests/FileLinkSettingsTests.cs b/src/Cake.Issues.Tests/FileLinkSettingsTests.cs index 7bb08f178..acbbed283 100644 --- a/src/Cake.Issues.Tests/FileLinkSettingsTests.cs +++ b/src/Cake.Issues.Tests/FileLinkSettingsTests.cs @@ -1,346 +1,79 @@ namespace Cake.Issues.Tests { using System; + using System.Collections.Generic; using Cake.Issues.Testing; using Shouldly; using Xunit; public sealed class FileLinkSettingsTests { - public sealed class TheGitHubBranchMethod + public sealed class TheCtor { [Fact] - public void Should_Throw_If_RepositoryUrl_Is_Null() + public void Should_Throw_If_Builder_Is_Null() { // Given - Uri repositoryUrl = null; - var branch = "master"; - var rootPath = string.Empty; + Func, Uri> builder = null; // When - var result = Record.Exception(() => - FileLinkSettings.GitHubBranch(repositoryUrl, branch, rootPath)); + var result = Record.Exception(() => new FileLinkSettings(builder)); // Then - result.IsArgumentNullException("repositoryUrl"); - } - - [Fact] - public void Should_Throw_If_Branch_Is_Null() - { - // Given - var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); - string branch = null; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.GitHubBranch(repositoryUrl, branch, rootPath)); - - // Then - result.IsArgumentNullException("branch"); - } - - [Fact] - public void Should_Throw_If_Branch_Is_Empty() - { - // Given - var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); - var branch = string.Empty; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.GitHubBranch(repositoryUrl, branch, rootPath)); - - // Then - result.IsArgumentOutOfRangeException("branch"); - } - - [Fact] - public void Should_Throw_If_Branch_Is_Whitespace() - { - // Given - var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); - var branch = " "; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.GitHubBranch(repositoryUrl, branch, rootPath)); - - // Then - result.IsArgumentOutOfRangeException("branch"); - } - - [Theory] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/{FilePath}#L{Line}-L{EndLine}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website/", "master", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/{FilePath}#L{Line}-L{EndLine}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}-L{EndLine}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "/foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}-L{EndLine}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo/", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/{FilePath}#L{Line}-L{EndLine}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "master", "foo/bar", "https://github.com/cake-contrib/Cake.Issues.Website/blob/master/foo/bar/{FilePath}#L{Line}-L{EndLine}")] - public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string branch, string rootPath, string expectedPattern) - { - // Given - - // When - var result = FileLinkSettings.GitHubBranch(new Uri(repositoryUrl), branch, rootPath); - - // Then - result.FileLinkPattern.ShouldBe(expectedPattern); + result.IsArgumentNullException("builder"); } } - public sealed class TheGitHubCommitMethod + public sealed class TheForGitHubMethod { [Fact] public void Should_Throw_If_RepositoryUrl_Is_Null() { // Given Uri repositoryUrl = null; - var commitId = "87eaf0a0cf1746179e8714eae4114d10"; - var rootPath = string.Empty; // When - var result = Record.Exception(() => - FileLinkSettings.GitHubCommit(repositoryUrl, commitId, rootPath)); + var result = Record.Exception(() => FileLinkSettings.ForGitHub(repositoryUrl)); // Then result.IsArgumentNullException("repositoryUrl"); } - - [Fact] - public void Should_Throw_If_CommitId_Is_Null() - { - // Given - var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); - string commitId = null; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.GitHubCommit(repositoryUrl, commitId, rootPath)); - - // Then - result.IsArgumentNullException("commitId"); - } - - [Fact] - public void Should_Throw_If_CommitId_Is_Empty() - { - // Given - var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); - var commitId = string.Empty; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.GitHubCommit(repositoryUrl, commitId, rootPath)); - - // Then - result.IsArgumentOutOfRangeException("commitId"); - } - - [Fact] - public void Should_Throw_If_CommitId_Is_Whitespace() - { - // Given - var repositoryUrl = new Uri("https://github.com/cake-contrib/Cake.Issues.Website"); - var commitId = " "; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.GitHubCommit(repositoryUrl, commitId, rootPath)); - - // Then - result.IsArgumentOutOfRangeException("commitId"); - } - - [Theory] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "87eaf0a0cf1746179e8714eae4114d10", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/{FilePath}#L{Line}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website/", "87eaf0a0cf1746179e8714eae4114d10", null, "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/{FilePath}#L{Line}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "87eaf0a0cf1746179e8714eae4114d10", "foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/foo/{FilePath}#L{Line}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "87eaf0a0cf1746179e8714eae4114d10", "/foo", "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/foo/{FilePath}#L{Line}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "87eaf0a0cf1746179e8714eae4114d10", "foo/", "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/foo/{FilePath}#L{Line}")] - [InlineData("https://github.com/cake-contrib/Cake.Issues.Website", "87eaf0a0cf1746179e8714eae4114d10", "foo/bar", "https://github.com/cake-contrib/Cake.Issues.Website/blob/87eaf0a0cf1746179e8714eae4114d10/foo/bar/{FilePath}#L{Line}")] - public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string commitId, string rootPath, string expectedPattern) - { - // Given - - // When - var result = FileLinkSettings.GitHubCommit(new Uri(repositoryUrl), commitId, rootPath); - - // Then - result.FileLinkPattern.ShouldBe(expectedPattern); - } } - public sealed class TheAzureDevOpsBranchMethod + public sealed class TheForAzureDevOpsMethod { [Fact] public void Should_Throw_If_RepositoryUrl_Is_Null() { // Given Uri repositoryUrl = null; - var branch = "master"; - var rootPath = string.Empty; // When - var result = Record.Exception(() => - FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath)); + var result = Record.Exception(() => FileLinkSettings.ForAzureDevOps(repositoryUrl)); // Then result.IsArgumentNullException("repositoryUrl"); } - - [Fact] - public void Should_Throw_If_Branch_Is_Null() - { - // Given - var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); - string branch = null; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath)); - - // Then - result.IsArgumentNullException("branch"); - } - - [Fact] - public void Should_Throw_If_Branch_Is_Empty() - { - // Given - var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); - var branch = string.Empty; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath)); - - // Then - result.IsArgumentOutOfRangeException("branch"); - } - - [Fact] - public void Should_Throw_If_Branch_Is_Whitespace() - { - // Given - var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); - var branch = " "; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath)); - - // Then - result.IsArgumentOutOfRangeException("branch"); - } - - [Theory] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", null, "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path={FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository/", "master", null, "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path={FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "/foo", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo/", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/{FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] - [InlineData("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", "master", "foo/bar", "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=foo/bar/{FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] - [InlineData("https://dev.azure.com/myorganization/_git/myrepo", "master", "foo/bar", "https://dev.azure.com/myorganization/_git/myrepo?path=foo/bar/{FilePath}&version=GBmaster&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] - public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string branch, string rootPath, string expectedPattern) - { - // Given - - // When - var result = FileLinkSettings.AzureDevOpsBranch(new Uri(repositoryUrl), branch, rootPath); - - // Then - result.FileLinkPattern.ShouldBe(expectedPattern); - } } - public sealed class TheAzureDevOpsCommitMethod + public sealed class TheGetFileLinkMethod { [Fact] - public void Should_Throw_If_RepositoryUrl_Is_Null() - { - // Given - Uri repositoryUrl = null; - var branch = "master"; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath)); - - // Then - result.IsArgumentNullException("repositoryUrl"); - } - - [Fact] - public void Should_Throw_If_CommitId_Is_Null() - { - // Given - var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); - string commitId = null; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.AzureDevOpsCommit(repositoryUrl, commitId, rootPath)); - - // Then - result.IsArgumentNullException("commitId"); - } - - [Fact] - public void Should_Throw_If_CommitId_Is_Empty() - { - // Given - var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); - var commitId = string.Empty; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.AzureDevOpsCommit(repositoryUrl, commitId, rootPath)); - - // Then - result.IsArgumentOutOfRangeException("commitId"); - } - - [Fact] - public void Should_Throw_If_CommitId_Is_Whitespace() - { - // Given - var repositoryUrl = new Uri("http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository"); - var commitId = " "; - var rootPath = string.Empty; - - // When - var result = Record.Exception(() => - FileLinkSettings.AzureDevOpsCommit(repositoryUrl, commitId, rootPath)); - - // Then - result.IsArgumentOutOfRangeException("commitId"); - } - - [Theory] - [InlineData("https://dev.azure.com/myorganization/_git/myrepo", "daf015105140e98d6f296e0db2a80d28b84e7f59", null, "https://dev.azure.com/myorganization/_git/myrepo?path={FilePath}&version=GCdaf015105140e98d6f296e0db2a80d28b84e7f59&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] - [InlineData("https://dev.azure.com/myorganization/_git/myrepo", "daf015105140e98d6f296e0db2a80d28b84e7f59", "foo/bar", "https://dev.azure.com/myorganization/_git/myrepo?path=foo/bar/{FilePath}&version=GCdaf015105140e98d6f296e0db2a80d28b84e7f59&line={Line}&lineEnd={EndLine}&lineStartColumn={Column}&lineEndColumn={EndColumn}")] - public void Should_Set_Correct_FileLinkPattern(string repositoryUrl, string commitId, string rootPath, string expectedPattern) + public void Should_Throw_If_Issue_Is_Null() { // Given + IIssue issue = null; // When - var result = FileLinkSettings.AzureDevOpsCommit(new Uri(repositoryUrl), commitId, rootPath); + var result = + Record.Exception(() => + FileLinkSettings + .ForGitHub(new Uri("https://github.com")) + .Branch("master") + .GetFileLink(issue)); // Then - result.FileLinkPattern.ShouldBe(expectedPattern); + result.IsArgumentNullException("issue"); } } } diff --git a/src/Cake.Issues.Tests/FileLinking/AzureDevOpsFileLinkSettingsBuilderTests.cs b/src/Cake.Issues.Tests/FileLinking/AzureDevOpsFileLinkSettingsBuilderTests.cs new file mode 100644 index 000000000..cb9f18c89 --- /dev/null +++ b/src/Cake.Issues.Tests/FileLinking/AzureDevOpsFileLinkSettingsBuilderTests.cs @@ -0,0 +1,411 @@ +namespace Cake.Issues.Tests.FileLinking +{ + using System; + using Cake.Issues.FileLinking; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + public sealed class AzureDevOpsFileLinkSettingsBuilderTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_RepositoryUrl_Is_Null() + { + // Given + Uri repositoryUrl = null; + + // When + var result = Record.Exception(() => new AzureDevOpsFileLinkSettingsBuilder(repositoryUrl)); + + // Then + result.IsArgumentNullException("repositoryUrl"); + } + } + + public sealed class TheBranchMethod + { + [Fact] + public void Should_Throw_If_BranchName_Is_Null() + { + // Given + string branch = null; + + // When + var result = + Record.Exception(() => new AzureDevOpsFileLinkSettingsBuilder(new Uri("https://github.com")).Branch(branch)); + + // Then + result.IsArgumentNullException("branchName"); + } + + [Fact] + public void Should_Throw_If_BranchName_Is_Empty() + { + // Given + var branch = string.Empty; + + // When + var result = + Record.Exception(() => new AzureDevOpsFileLinkSettingsBuilder(new Uri("https://github.com")).Branch(branch)); + + // Then + result.IsArgumentOutOfRangeException("branchName"); + } + + [Fact] + public void Should_Throw_If_BranchName_Is_WhiteSpace() + { + // Given + var branch = " "; + + // When + var result = + Record.Exception(() => new AzureDevOpsFileLinkSettingsBuilder(new Uri("https://github.com")).Branch(branch)); + + // Then + result.IsArgumentOutOfRangeException("branchName"); + } + + [Theory] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + 12, + 20, + 30, + "master", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster&line=10&lineEnd=12&lineStartColumn=20&lineEndColumn=30")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo/", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + 12, + 20, + 30, + "master", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster&line=10&lineEnd=12&lineStartColumn=20&lineEndColumn=30")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + 12, + 20, + null, + "master", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster&line=10&lineEnd=12&lineStartColumn=20&lineEndColumn=2147483647")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + 12, + null, + null, + "master", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster&line=10&lineEnd=12&lineStartColumn=1&lineEndColumn=2147483647")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + null, + null, + null, + "master", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster&line=10&lineEnd=10&lineStartColumn=1&lineEndColumn=2147483647")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + null, + null, + null, + null, + "master", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster")] + [InlineData( + "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + 12, + 20, + 30, + "master", + "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster&line=10&lineEnd=12&lineStartColumn=20&lineEndColumn=30")] + public void Should_Return_The_Correct_Link( + string repositoryUrl, + string filePath, + int? line, + int? endLine, + int? column, + int? endColumn, + string branch, + string expectedLink) + { + // Given + var issue = + IssueBuilder + .NewIssue("Foo", "ProviderTypeFoo", "ProviderNameFoo") + .InFile(filePath, line, endLine, column, endColumn) + .Create(); + + // When + var result = + new AzureDevOpsFileLinkSettingsBuilder(new Uri(repositoryUrl)) + .Branch(branch) + .GetFileLink(issue); + + // Then + result.ToString().ShouldBe(expectedLink); + } + + [Theory] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + "foo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + "master", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/foo/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + "/foo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + "master", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/foo/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + "foo/", + @"src\ClassLibrary1\ClassLibrary1.csproj", + "master", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/foo/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + "foo/bar", + @"src\ClassLibrary1\ClassLibrary1.csproj", + "master", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/foo/bar/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + null, + @"src\ClassLibrary1\ClassLibrary1.csproj", + "master", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GBmaster")] + public void Should_Return_The_Correct_Link_For_RootPath( + string repositoryUrl, + string rootPath, + string filePath, + string branch, + string expectedLink) + { + // Given + var issue = + IssueBuilder + .NewIssue("Foo", "ProviderTypeFoo", "ProviderNameFoo") + .InFile(filePath) + .Create(); + + // When + var result = + new AzureDevOpsFileLinkSettingsBuilder(new Uri(repositoryUrl)) + .Branch(branch) + .WithRootPath(rootPath) + .GetFileLink(issue); + + // Then + result.ToString().ShouldBe(expectedLink); + } + } + + public sealed class TheCommitMethod + { + [Fact] + public void Should_Throw_If_CommitId_Is_Null() + { + // Given + string commitId = null; + + // When + var result = + Record.Exception(() => new AzureDevOpsFileLinkSettingsBuilder(new Uri("https://github.com")).Commit(commitId)); + + // Then + result.IsArgumentNullException("commitId"); + } + + [Fact] + public void Should_Throw_If_CommitId_Is_Empty() + { + // Given + var commitId = string.Empty; + + // When + var result = + Record.Exception(() => new AzureDevOpsFileLinkSettingsBuilder(new Uri("https://github.com")).Commit(commitId)); + + // Then + result.IsArgumentOutOfRangeException("commitId"); + } + + [Fact] + public void Should_Throw_If_CommitId_Is_WhiteSpace() + { + // Given + var commitId = " "; + + // When + var result = + Record.Exception(() => new AzureDevOpsFileLinkSettingsBuilder(new Uri("https://github.com")).Commit(commitId)); + + // Then + result.IsArgumentOutOfRangeException("commitId"); + } + + [Theory] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + 12, + 20, + 30, + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466&line=10&lineEnd=12&lineStartColumn=20&lineEndColumn=30")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo/", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + 12, + 20, + 30, + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466&line=10&lineEnd=12&lineStartColumn=20&lineEndColumn=30")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + 12, + 20, + null, + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466&line=10&lineEnd=12&lineStartColumn=20&lineEndColumn=2147483647")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + 12, + null, + null, + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466&line=10&lineEnd=12&lineStartColumn=1&lineEndColumn=2147483647")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + null, + null, + null, + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466&line=10&lineEnd=10&lineStartColumn=1&lineEndColumn=2147483647")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + null, + null, + null, + null, + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466")] + [InlineData( + "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository", + @"src\ClassLibrary1\ClassLibrary1.csproj", + 10, + 12, + 20, + 30, + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466&line=10&lineEnd=12&lineStartColumn=20&lineEndColumn=30")] + public void Should_Return_The_Correct_Link( + string repositoryUrl, + string filePath, + int? line, + int? endLine, + int? column, + int? endColumn, + string commitId, + string expectedLink) + { + // Given + var issue = + IssueBuilder + .NewIssue("Foo", "ProviderTypeFoo", "ProviderNameFoo") + .InFile(filePath, line, endLine, column, endColumn) + .Create(); + + // When + var result = + new AzureDevOpsFileLinkSettingsBuilder(new Uri(repositoryUrl)) + .Commit(commitId) + .GetFileLink(issue); + + // Then + result.ToString().ShouldBe(expectedLink); + } + + [Theory] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + "foo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/foo/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + "/foo", + @"src\ClassLibrary1\ClassLibrary1.csproj", + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/foo/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + "foo/", + @"src\ClassLibrary1\ClassLibrary1.csproj", + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/foo/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + "foo/bar", + @"src\ClassLibrary1\ClassLibrary1.csproj", + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/foo/bar/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466")] + [InlineData( + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo", + null, + @"src\ClassLibrary1\ClassLibrary1.csproj", + "734bd70b03e45741426ed2916d1fa72c6ff20466", + "https://dev.azure.com/pberger/_git/Cake.Issues-Demo?path=/src/ClassLibrary1/ClassLibrary1.csproj&version=GC734bd70b03e45741426ed2916d1fa72c6ff20466")] + public void Should_Return_The_Correct_Link_For_RootPath( + string repositoryUrl, + string rootPath, + string filePath, + string commitId, + string expectedLink) + { + // Given + var issue = + IssueBuilder + .NewIssue("Foo", "ProviderTypeFoo", "ProviderNameFoo") + .InFile(filePath) + .Create(); + + // When + var result = + new AzureDevOpsFileLinkSettingsBuilder(new Uri(repositoryUrl)) + .Commit(commitId) + .WithRootPath(rootPath) + .GetFileLink(issue); + + // Then + result.ToString().ShouldBe(expectedLink); + } + } + } +} diff --git a/src/Cake.Issues.Tests/FileLinking/FileLinkOptionalSettingsBuilderTests.cs b/src/Cake.Issues.Tests/FileLinking/FileLinkOptionalSettingsBuilderTests.cs new file mode 100644 index 000000000..75f48322e --- /dev/null +++ b/src/Cake.Issues.Tests/FileLinking/FileLinkOptionalSettingsBuilderTests.cs @@ -0,0 +1,98 @@ +namespace Cake.Issues.Tests.FileLinking +{ + using System; + using System.Collections.Generic; + using Cake.Issues.FileLinking; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + public sealed class FileLinkOptionalSettingsBuilderTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Builder_Is_Null() + { + // Given + Func, Uri> builder = null; + + // When + var result = Record.Exception(() => new FileLinkOptionalSettingsBuilder(builder)); + + // Then + result.IsArgumentNullException("builder"); + } + } + + public sealed class TheWithRootPathMethod + { + [Fact] + public void Should_Not_Throw_If_RootPath_Is_Null() + { + // Given + string rootPath = null; + + // When + var result = + new AzureDevOpsFileLinkSettingsBuilder(new Uri("https://github.com")) + .Branch("master") + .WithRootPath(rootPath); + + // Then + result.ShouldNotBeNull(); + } + + [Fact] + public void Should_Throw_If_RootPath_Is_Empty() + { + // Given + var rootPath = string.Empty; + + // When + var result = + Record.Exception(() => + new AzureDevOpsFileLinkSettingsBuilder(new Uri("https://github.com")) + .Branch("master") + .WithRootPath(rootPath)); + + // Then + result.IsArgumentOutOfRangeException("rootPath"); + } + + [Fact] + public void Should_Throw_If_RootPath_Is_WhiteSpace() + { + // Given + var rootPath = " "; + + // When + var result = + Record.Exception(() => + new AzureDevOpsFileLinkSettingsBuilder(new Uri("https://github.com")) + .Branch("master") + .WithRootPath(rootPath)); + + // Then + result.IsArgumentOutOfRangeException("rootPath"); + } + + [Theory] + [InlineData("foo\tbar")] + public void Should_Throw_If_RootPath_Is_Invalid(string rootPath) + { + // Given + + // When + var result = + Record.Exception(() => + new AzureDevOpsFileLinkSettingsBuilder(new Uri("https://github.com")) + .Branch("master") + .WithRootPath(rootPath)); + + // Then + result.IsArgumentException("rootPath"); + } + } + } +} diff --git a/src/Cake.Issues.Tests/FileLinking/GitHubFileLinkSettingsBuilderTests.cs b/src/Cake.Issues.Tests/FileLinking/GitHubFileLinkSettingsBuilderTests.cs new file mode 100644 index 000000000..7db305c89 --- /dev/null +++ b/src/Cake.Issues.Tests/FileLinking/GitHubFileLinkSettingsBuilderTests.cs @@ -0,0 +1,339 @@ +namespace Cake.Issues.Tests.FileLinking +{ + using System; + using Cake.Issues.FileLinking; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + public sealed class GitHubFileLinkSettingsBuilderTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_RepositoryUrl_Is_Null() + { + // Given + Uri repositoryUrl = null; + + // When + var result = Record.Exception(() => new GitHubFileLinkSettingsBuilder(repositoryUrl)); + + // Then + result.IsArgumentNullException("repositoryUrl"); + } + } + + public sealed class TheBranchMethod + { + [Fact] + public void Should_Throw_If_BranchName_Is_Null() + { + // Given + string branch = null; + + // When + var result = + Record.Exception(() => new GitHubFileLinkSettingsBuilder(new Uri("https://github.com")).Branch(branch)); + + // Then + result.IsArgumentNullException("branchName"); + } + + [Fact] + public void Should_Throw_If_BranchName_Is_Empty() + { + // Given + var branch = string.Empty; + + // When + var result = + Record.Exception(() => new GitHubFileLinkSettingsBuilder(new Uri("https://github.com")).Branch(branch)); + + // Then + result.IsArgumentOutOfRangeException("branchName"); + } + + [Fact] + public void Should_Throw_If_BranchName_Is_WhiteSpace() + { + // Given + var branch = " "; + + // When + var result = + Record.Exception(() => new GitHubFileLinkSettingsBuilder(new Uri("https://github.com")).Branch(branch)); + + // Then + result.IsArgumentOutOfRangeException("branchName"); + } + + [Theory] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues", + @"src\Cake.Issues\Cake.Issues.csproj", + 10, + 12, + "master", + "https://github.com/cake-contrib/Cake.Issues/blob/master/src/Cake.Issues/Cake.Issues.csproj#L10-L12")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + @"src\Cake.Issues\Cake.Issues.csproj", + 10, + 12, + "master", + "https://github.com/cake-contrib/Cake.Issues/blob/master/src/Cake.Issues/Cake.Issues.csproj#L10-L12")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + @"src\Cake.Issues\Cake.Issues.csproj", + 10, + null, + "master", + "https://github.com/cake-contrib/Cake.Issues/blob/master/src/Cake.Issues/Cake.Issues.csproj#L10")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + @"src\Cake.Issues\Cake.Issues.csproj", + null, + null, + "master", + "https://github.com/cake-contrib/Cake.Issues/blob/master/src/Cake.Issues/Cake.Issues.csproj")] + public void Should_Return_The_Correct_Link( + string repositoryUrl, + string filePath, + int? line, + int? endLine, + string branch, + string expectedLink) + { + // Given + var issue = + IssueBuilder + .NewIssue("Foo", "ProviderTypeFoo", "ProviderNameFoo") + .InFile(filePath, line, endLine, null, null) + .Create(); + + // When + var result = + new GitHubFileLinkSettingsBuilder(new Uri(repositoryUrl)) + .Branch(branch) + .GetFileLink(issue); + + // Then + result.ToString().ShouldBe(expectedLink); + } + + [Theory] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + "foo", + @"src\Cake.Issues\Cake.Issues.csproj", + "master", + "https://github.com/cake-contrib/Cake.Issues/blob/master/foo/src/Cake.Issues/Cake.Issues.csproj")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + "/foo", + @"src\Cake.Issues\Cake.Issues.csproj", + "master", + "https://github.com/cake-contrib/Cake.Issues/blob/master/foo/src/Cake.Issues/Cake.Issues.csproj")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + "foo/", + @"src\Cake.Issues\Cake.Issues.csproj", + "master", + "https://github.com/cake-contrib/Cake.Issues/blob/master/foo/src/Cake.Issues/Cake.Issues.csproj")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + "foo/bar", + @"src\Cake.Issues\Cake.Issues.csproj", + "master", + "https://github.com/cake-contrib/Cake.Issues/blob/master/foo/bar/src/Cake.Issues/Cake.Issues.csproj")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + null, + @"src\Cake.Issues\Cake.Issues.csproj", + "master", + "https://github.com/cake-contrib/Cake.Issues/blob/master/src/Cake.Issues/Cake.Issues.csproj")] + public void Should_Return_The_Correct_Link_For_RootPath( + string repositoryUrl, + string rootPath, + string filePath, + string branch, + string expectedLink) + { + // Given + var issue = + IssueBuilder + .NewIssue("Foo", "ProviderTypeFoo", "ProviderNameFoo") + .InFile(filePath) + .Create(); + + // When + var result = + new GitHubFileLinkSettingsBuilder(new Uri(repositoryUrl)) + .Branch(branch) + .WithRootPath(rootPath) + .GetFileLink(issue); + + // Then + result.ToString().ShouldBe(expectedLink); + } + } + + public sealed class TheCommitMethod + { + [Fact] + public void Should_Throw_If_CommitId_Is_Null() + { + // Given + string commitId = null; + + // When + var result = + Record.Exception(() => new GitHubFileLinkSettingsBuilder(new Uri("https://github.com")).Commit(commitId)); + + // Then + result.IsArgumentNullException("commitId"); + } + + [Fact] + public void Should_Throw_If_CommitId_Is_Empty() + { + // Given + var commitId = string.Empty; + + // When + var result = + Record.Exception(() => new GitHubFileLinkSettingsBuilder(new Uri("https://github.com")).Commit(commitId)); + + // Then + result.IsArgumentOutOfRangeException("commitId"); + } + + [Fact] + public void Should_Throw_If_CommitId_Is_WhiteSpace() + { + // Given + var commitId = " "; + + // When + var result = + Record.Exception(() => new GitHubFileLinkSettingsBuilder(new Uri("https://github.com")).Commit(commitId)); + + // Then + result.IsArgumentOutOfRangeException("commitId"); + } + + [Theory] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues", + @"src\Cake.Issues\Cake.Issues.csproj", + 10, + 12, + "6d035013812a4a3ab8be5e84c0f2a8b5ce60720a", + "https://github.com/cake-contrib/Cake.Issues/blob/6d035013812a4a3ab8be5e84c0f2a8b5ce60720a/src/Cake.Issues/Cake.Issues.csproj#L10-L12")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + @"src\Cake.Issues\Cake.Issues.csproj", + 10, + 12, + "6d035013812a4a3ab8be5e84c0f2a8b5ce60720a", + "https://github.com/cake-contrib/Cake.Issues/blob/6d035013812a4a3ab8be5e84c0f2a8b5ce60720a/src/Cake.Issues/Cake.Issues.csproj#L10-L12")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + @"src\Cake.Issues\Cake.Issues.csproj", + 10, + null, + "6d035013812a4a3ab8be5e84c0f2a8b5ce60720a", + "https://github.com/cake-contrib/Cake.Issues/blob/6d035013812a4a3ab8be5e84c0f2a8b5ce60720a/src/Cake.Issues/Cake.Issues.csproj#L10")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + @"src\Cake.Issues\Cake.Issues.csproj", + null, + null, + "6d035013812a4a3ab8be5e84c0f2a8b5ce60720a", + "https://github.com/cake-contrib/Cake.Issues/blob/6d035013812a4a3ab8be5e84c0f2a8b5ce60720a/src/Cake.Issues/Cake.Issues.csproj")] + public void Should_Return_The_Correct_Link( + string repositoryUrl, + string filePath, + int? line, + int? endLine, + string commitId, + string expectedLink) + { + // Given + var issue = + IssueBuilder + .NewIssue("Foo", "ProviderTypeFoo", "ProviderNameFoo") + .InFile(filePath, line, endLine, null, null) + .OfRule("Foo") + .WithPriority(IssuePriority.Warning) + .Create(); + + // When + var result = + new GitHubFileLinkSettingsBuilder(new Uri(repositoryUrl)) + .Commit(commitId) + .GetFileLink(issue); + + // Then + result.ToString().ShouldBe(expectedLink); + } + + [Theory] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + "foo", + @"src\Cake.Issues\Cake.Issues.csproj", + "6d035013812a4a3ab8be5e84c0f2a8b5ce60720a", + "https://github.com/cake-contrib/Cake.Issues/blob/6d035013812a4a3ab8be5e84c0f2a8b5ce60720a/foo/src/Cake.Issues/Cake.Issues.csproj")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + "/foo", + @"src\Cake.Issues\Cake.Issues.csproj", + "6d035013812a4a3ab8be5e84c0f2a8b5ce60720a", + "https://github.com/cake-contrib/Cake.Issues/blob/6d035013812a4a3ab8be5e84c0f2a8b5ce60720a/foo/src/Cake.Issues/Cake.Issues.csproj")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + "foo/", + @"src\Cake.Issues\Cake.Issues.csproj", + "6d035013812a4a3ab8be5e84c0f2a8b5ce60720a", + "https://github.com/cake-contrib/Cake.Issues/blob/6d035013812a4a3ab8be5e84c0f2a8b5ce60720a/foo/src/Cake.Issues/Cake.Issues.csproj")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + "foo/bar", + @"src\Cake.Issues\Cake.Issues.csproj", + "6d035013812a4a3ab8be5e84c0f2a8b5ce60720a", + "https://github.com/cake-contrib/Cake.Issues/blob/6d035013812a4a3ab8be5e84c0f2a8b5ce60720a/foo/bar/src/Cake.Issues/Cake.Issues.csproj")] + [InlineData( + "https://github.com/cake-contrib/Cake.Issues/", + null, + @"src\Cake.Issues\Cake.Issues.csproj", + "6d035013812a4a3ab8be5e84c0f2a8b5ce60720a", + "https://github.com/cake-contrib/Cake.Issues/blob/6d035013812a4a3ab8be5e84c0f2a8b5ce60720a/src/Cake.Issues/Cake.Issues.csproj")] + public void Should_Return_The_Correct_Link_For_RootPath( + string repositoryUrl, + string rootPath, + string filePath, + string commitId, + string expectedLink) + { + // Given + var issue = + IssueBuilder + .NewIssue("Foo", "ProviderTypeFoo", "ProviderNameFoo") + .InFile(filePath) + .Create(); + + // When + var result = + new GitHubFileLinkSettingsBuilder(new Uri(repositoryUrl)) + .Commit(commitId) + .WithRootPath(rootPath) + .GetFileLink(issue); + + // Then + result.ToString().ShouldBe(expectedLink); + } + } + } +} diff --git a/src/Cake.Issues.Tests/FileLinking/IDictionaryExtensionsTests.cs b/src/Cake.Issues.Tests/FileLinking/IDictionaryExtensionsTests.cs new file mode 100644 index 000000000..430b7705d --- /dev/null +++ b/src/Cake.Issues.Tests/FileLinking/IDictionaryExtensionsTests.cs @@ -0,0 +1,55 @@ +namespace Cake.Issues.Tests.FileLinking +{ + using Cake.Issues.FileLinking; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + public sealed class IDictionaryExtensionsTests + { + public sealed class TheGetValueOrDefaultExtension + { + [Fact] + public void Should_Throw_If_Dictionary_Is_Null() + { + // Given + System.Collections.Generic.IDictionary dictionary = null; + + // When + var result = Record.Exception(() => dictionary.GetValueOrDefault("foo", null)); + + // Then + result.IsArgumentNullException("dictionary"); + } + + [Fact] + public void Should_Return_Value_If_Exists() + { + // Given + var key = "foo"; + var value = "bar"; + var dictionary = new System.Collections.Generic.Dictionary { { key, value } }; + + // When + var result = dictionary.GetValueOrDefault(key, null); + + // Then + result.ShouldBe(value); + } + + [Fact] + public void Should_Return_DefaultValue_If_Value_Does_Not_Exist() + { + // Given + var defaultValue = "defaultValue"; + var dictionary = new System.Collections.Generic.Dictionary { { "foo", "bar" } }; + + // When + var result = dictionary.GetValueOrDefault("bar", defaultValue); + + // Then + result.ShouldBe(defaultValue); + } + } + } +} diff --git a/src/Cake.Issues.Tests/IssueReaderTests.cs b/src/Cake.Issues.Tests/IssueReaderTests.cs index 08a02df78..de69051c1 100644 --- a/src/Cake.Issues.Tests/IssueReaderTests.cs +++ b/src/Cake.Issues.Tests/IssueReaderTests.cs @@ -367,10 +367,7 @@ public void Should_Set_FileLink_Property() var repoUrl = "https://github.com/cake-contrib/Cake.Issues.Website"; var branch = "develop"; fixture.Settings.FileLinkSettings = - FileLinkSettings.GitHubBranch( - new System.Uri(repoUrl), - branch, - null); + FileLinkSettings.ForGitHub(new System.Uri(repoUrl)).Branch(branch); // When var issues = fixture.ReadIssues().ToList(); @@ -382,7 +379,7 @@ public void Should_Set_FileLink_Property() .ShouldBe($"{repoUrl}/blob/{branch}/{filePath1.Replace(@"\", "/")}#L{line1}-L{endLine1}"); issues.ShouldContain(issue2); issue2.FileLink.ToString() - .ShouldBe($"{repoUrl}/blob/{branch}/{filePath2.Replace(@"\", "/")}#L{line2}-L"); + .ShouldBe($"{repoUrl}/blob/{branch}/{filePath2.Replace(@"\", "/")}#L{line2}"); } } } diff --git a/src/Cake.Issues/Aliases.FileLinking.cs b/src/Cake.Issues/Aliases.FileLinking.cs index 03127102b..b29edf204 100644 --- a/src/Cake.Issues/Aliases.FileLinking.cs +++ b/src/Cake.Issues/Aliases.FileLinking.cs @@ -40,7 +40,7 @@ public static FileLinkSettings IssueFileLinkSettingsForGitHubBranch( /// eg. https://github.com/cake-contrib/Cake.Issues.Reporting.Generic. /// Name of the branch on which the file linking will be based on. /// Root path of the files. - /// null or if files are in the root of the repository. + /// null if files are in the root of the repository. /// Settings for linking to files hosted in GitHub. [CakeMethodAlias] [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] @@ -54,7 +54,11 @@ public static FileLinkSettings IssueFileLinkSettingsForGitHubBranch( repositoryUrl.NotNull(nameof(repositoryUrl)); branch.NotNullOrWhiteSpace(nameof(branch)); - return FileLinkSettings.GitHubBranch(repositoryUrl, branch, rootPath); + return + FileLinkSettings + .ForGitHub(repositoryUrl) + .Branch(branch) + .WithRootPath(rootPath); } /// @@ -102,7 +106,11 @@ public static FileLinkSettings IssueFileLinkSettingsForGitHubCommit( repositoryUrl.NotNull(nameof(repositoryUrl)); commitId.NotNullOrWhiteSpace(nameof(commitId)); - return FileLinkSettings.GitHubCommit(repositoryUrl, commitId, rootPath); + return + FileLinkSettings + .ForGitHub(repositoryUrl) + .Commit(commitId) + .WithRootPath(rootPath); } /// @@ -137,7 +145,7 @@ public static FileLinkSettings IssueFileLinkSettingsForAzureDevOpsBranch( /// eg. https://dev.azure.com/myorganization/_git/myrepo. /// Name of the branch on which the file linking will be based on. /// Root path of the files. - /// null or if files are in the root of the repository. + /// null if files are in the root of the repository. /// Settings for linking files hosted on Azure DevOps. [CakeMethodAlias] [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] @@ -151,7 +159,11 @@ public static FileLinkSettings IssueFileLinkSettingsForAzureDevOpsBranch( repositoryUrl.NotNull(nameof(repositoryUrl)); branch.NotNullOrWhiteSpace(nameof(branch)); - return FileLinkSettings.AzureDevOpsBranch(repositoryUrl, branch, rootPath); + return + FileLinkSettings + .ForAzureDevOps(repositoryUrl) + .Branch(branch) + .WithRootPath(rootPath); } /// @@ -186,7 +198,7 @@ public static FileLinkSettings IssueFileLinkSettingsForAzureDevOpsCommit( /// eg. https://dev.azure.com/myorganization/_git/myrepo. /// The commit id on which the file linking will be based on. /// Root path of the files. - /// null or if files are in the root of the repository. + /// null if files are in the root of the repository. /// Settings for linking files hosted on Azure DevOps. [CakeMethodAlias] [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] @@ -200,7 +212,11 @@ public static FileLinkSettings IssueFileLinkSettingsForAzureDevOpsCommit( repositoryUrl.NotNull(nameof(repositoryUrl)); commitId.NotNullOrWhiteSpace(nameof(commitId)); - return FileLinkSettings.AzureDevOpsCommit(repositoryUrl, commitId, rootPath); + return + FileLinkSettings + .ForAzureDevOps(repositoryUrl) + .Commit(commitId) + .WithRootPath(rootPath); } } } diff --git a/src/Cake.Issues/FileLinkSettings.cs b/src/Cake.Issues/FileLinkSettings.cs index 472bd4913..7ec2e497e 100644 --- a/src/Cake.Issues/FileLinkSettings.cs +++ b/src/Cake.Issues/FileLinkSettings.cs @@ -1,140 +1,64 @@ namespace Cake.Issues { using System; + using System.Collections.Generic; + using Cake.Issues.FileLinking; /// /// Settings how issues should be linked to files. /// public class FileLinkSettings { + private readonly Func, Uri> builder; + /// /// Initializes a new instance of the class. /// - /// Pattern which should be used to link issues to files. - public FileLinkSettings(string fileLinkPattern) + /// Callback called for building the file link. + internal FileLinkSettings(Func, Uri> builder) { - fileLinkPattern.NotNullOrWhiteSpace(nameof(fileLinkPattern)); + builder.NotNull(nameof(builder)); - this.FileLinkPattern = fileLinkPattern; + this.builder = builder; } /// - /// Gets the pattern which should be used to link issues to files. - /// Fields in the form {FieldName} are replaced with the value of the issue. - /// All fields of are supported. - /// See - /// to receive the resolved URL to the file. + /// Returns the URL to the file on the source code hosting system + /// for the issue . /// - public string FileLinkPattern { get; } - - /// - /// Returns settings for linking to files hosted in GitHub on a specific branch. - /// - /// Full URL of the Git repository, - /// eg. https://github.com/cake-contrib/Cake.Issues. - /// Name of the branch. - /// Root path of the files. - /// null or if files are in the root of the repository. - /// Settings for linking to files hosted in GitHub. - public static FileLinkSettings GitHubBranch( - Uri repositoryUrl, - string branch, - string rootPath) + /// Issue for which the link should be returned. + /// URL to the file on the source code hosting system. + public Uri GetFileLink(IIssue issue) { - repositoryUrl.NotNull(nameof(repositoryUrl)); - branch.NotNullOrWhiteSpace(nameof(branch)); + issue.NotNull(nameof(issue)); - return - new FileLinkSettings( - repositoryUrl.Append("blob", branch, rootPath, "{FilePath}#L{Line}-L{EndLine}").ToString()); + return this.builder(issue, new Dictionary()); } /// - /// Returns settings for linking to files hosted in GitHub for a specific commit. + /// Returns builder class for settings for linking to files hosted in GitHub. /// /// Full URL of the Git repository, /// eg. https://github.com/cake-contrib/Cake.Issues. - /// The commit id on which the file linking will be based on. - /// Root path of the files. - /// null or if files are in the root of the repository. - /// Settings for linking to files hosted in GitHub. - public static FileLinkSettings GitHubCommit( - Uri repositoryUrl, - string commitId, - string rootPath) - { - repositoryUrl.NotNull(nameof(repositoryUrl)); - commitId.NotNullOrWhiteSpace(nameof(commitId)); - - return - new FileLinkSettings( - repositoryUrl.Append("blob", commitId, rootPath, "{FilePath}#L{Line}").ToString()); - } - - /// - /// Returns settings for linking to files hosted in Azure DevOps on a specific branch. - /// - /// Full URL of the Git repository, - /// e.g. https://dev.azure.com/myorganization/_git/myrepo. - /// Name of the branch. - /// Root path of the files. - /// null or if files are in the root of the repository. - /// Settings for linking to files hosted in Azure DevOps. - public static FileLinkSettings AzureDevOpsBranch( - Uri repositoryUrl, - string branch, - string rootPath) + /// Builder class for the settings. + internal static GitHubFileLinkSettingsBuilder ForGitHub(Uri repositoryUrl) { repositoryUrl.NotNull(nameof(repositoryUrl)); - branch.NotNullOrWhiteSpace(nameof(branch)); - if (!string.IsNullOrWhiteSpace(rootPath)) - { - rootPath = rootPath.Trim('/') + "/"; - } - - return - new FileLinkSettings( - repositoryUrl.ToString().TrimEnd('/') + - "?path=" + rootPath + "{FilePath}" + - "&version=GB" + branch + - "&line={Line}" + - "&lineEnd={EndLine}" + - "&lineStartColumn={Column}" + - "&lineEndColumn={EndColumn}"); + return new GitHubFileLinkSettingsBuilder(repositoryUrl); } /// - /// Returns settings for linking to files hosted in Azure DevOps for a specific commit id. + /// Returns builder class for settings for linking to files hosted in Azure DevOps. /// /// Full URL of the Git repository, /// e.g. https://dev.azure.com/myorganization/_git/myrepo. - /// The commit id on which the file linking will be based on. - /// Root path of the files. - /// null or if files are in the root of the repository. - /// Settings for linking to files hosted in Azure DevOps. - public static FileLinkSettings AzureDevOpsCommit( - Uri repositoryUrl, - string commitId, - string rootPath) + /// Builder class for the settings. + internal static AzureDevOpsFileLinkSettingsBuilder ForAzureDevOps(Uri repositoryUrl) { repositoryUrl.NotNull(nameof(repositoryUrl)); - commitId.NotNullOrWhiteSpace(nameof(commitId)); - - if (!string.IsNullOrWhiteSpace(rootPath)) - { - rootPath = rootPath.Trim('/') + "/"; - } - return - new FileLinkSettings( - repositoryUrl.ToString().TrimEnd('/') + - "?path=" + rootPath + "{FilePath}" + - "&version=GC" + commitId + - "&line={Line}" + - "&lineEnd={EndLine}" + - "&lineStartColumn={Column}" + - "&lineEndColumn={EndColumn}"); + return new AzureDevOpsFileLinkSettingsBuilder(repositoryUrl); } } } diff --git a/src/Cake.Issues/FileLinkSettingsExtensions.cs b/src/Cake.Issues/FileLinkSettingsExtensions.cs deleted file mode 100644 index 4ac21f6cd..000000000 --- a/src/Cake.Issues/FileLinkSettingsExtensions.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Cake.Issues -{ - using System; - - /// - /// Extensions for . - /// - public static class FileLinkSettingsExtensions - { - /// - /// Returns the URL to the file on the source code hosting system - /// defined by for the issue . - /// - /// Settings describing the source code hosting. - /// Issue for which the link should be returned. - /// URL to the file on the source code hosting system. - public static Uri GetFileLink(this FileLinkSettings settings, IIssue issue) - { - settings.NotNull(nameof(settings)); - issue.NotNull(nameof(issue)); - - return new Uri(settings.FileLinkPattern.ReplaceIssuePattern(issue)); - } - } -} diff --git a/src/Cake.Issues/FileLinking/AzureDevOpsFileLinkSettingsBuilder.cs b/src/Cake.Issues/FileLinking/AzureDevOpsFileLinkSettingsBuilder.cs new file mode 100644 index 000000000..74e5a3f27 --- /dev/null +++ b/src/Cake.Issues/FileLinking/AzureDevOpsFileLinkSettingsBuilder.cs @@ -0,0 +1,97 @@ +namespace Cake.Issues.FileLinking +{ + using System; + using System.Collections.Generic; + + /// + /// Class for building settings for file links of files hosted on Azure DevOps. + /// + internal class AzureDevOpsFileLinkSettingsBuilder + { + private readonly Uri repositoryUrl; + + /// + /// Initializes a new instance of the class. + /// + /// Full URL of the Git repository, + /// eg. https://github.com/cake-contrib/Cake.Issues. + internal AzureDevOpsFileLinkSettingsBuilder(Uri repositoryUrl) + { + repositoryUrl.NotNull(nameof(repositoryUrl)); + + this.repositoryUrl = repositoryUrl; + } + + /// + /// Returns settings to files on AzureDevOps on a specific branch. + /// + /// Name of the branch. + /// Class for setting additional settings. + public FileLinkOptionalSettingsBuilder Branch(string branchName) + { + branchName.NotNullOrWhiteSpace(nameof(branchName)); + + return + new FileLinkOptionalSettingsBuilder( + (issue, values) => + { + issue.NotNull(nameof(issue)); + values.NotNull(nameof(values)); + + var fileLinkPattern = + this.GetFileLinkPattern(issue, values, "GB", branchName); + return new Uri(fileLinkPattern.ReplaceIssuePattern(issue)); + }); + } + + /// + /// Returns settings to files on AzureDevOps on a specific commit. + /// + /// The commit id on which the file linking will be based on. + /// Class for setting additional settings. + public FileLinkOptionalSettingsBuilder Commit(string commitId) + { + commitId.NotNullOrWhiteSpace(nameof(commitId)); + + return + new FileLinkOptionalSettingsBuilder( + (issue, values) => + { + issue.NotNull(nameof(issue)); + values.NotNull(nameof(values)); + + var fileLinkPattern = + this.GetFileLinkPattern(issue, values, "GC", commitId); + return new Uri(fileLinkPattern.ReplaceIssuePattern(issue)); + }); + } + + private string GetFileLinkPattern( + IIssue issue, + IDictionary values, + string versionType, + string version) + { + issue.NotNull(nameof(issue)); + values.NotNull(nameof(values)); + versionType.NotNullOrWhiteSpace(nameof(versionType)); + version.NotNullOrWhiteSpace(nameof(version)); + + var result = + this.repositoryUrl.ToString().TrimEnd('/') + + "?path=/" + values.GetValueOrDefault("rootPath", null)?.TrimStart('/').WithEnding("/") + "{FilePath}" + + "&version=" + versionType + version; + + if (issue.Line.HasValue) + { + result += + "&line={Line}" + + "&lineEnd=" + (issue.EndLine.HasValue ? "{EndLine}" : "{Line}") + + "&lineStartColumn=" + (issue.Column.HasValue ? "{Column}" : "1") + + "&lineEndColumn=" + (issue.EndColumn.HasValue ? "{EndColumn}" : int.MaxValue.ToString()); + } + + return result; + } + } +} diff --git a/src/Cake.Issues/FileLinking/FileLinkOptionalSettingsBuilder.cs b/src/Cake.Issues/FileLinking/FileLinkOptionalSettingsBuilder.cs new file mode 100644 index 000000000..d193b9d03 --- /dev/null +++ b/src/Cake.Issues/FileLinking/FileLinkOptionalSettingsBuilder.cs @@ -0,0 +1,53 @@ +namespace Cake.Issues.FileLinking +{ + using System; + using System.Collections.Generic; + + /// + /// Class containing builder for optional settings for linking to files. + /// + internal class FileLinkOptionalSettingsBuilder : FileLinkSettings + { + private readonly Func, Uri> builder; + + /// + /// Initializes a new instance of the class. + /// + /// Callback called for building the file link. + internal FileLinkOptionalSettingsBuilder(Func, Uri> builder) + : base(builder) + { + builder.NotNull(nameof(builder)); + + this.builder = builder; + } + + /// + /// Sets the root path for the files. + /// + /// Root path for the files. + /// null if files are in the root of the repository. + /// Object for creating the file link. + public FileLinkSettings WithRootPath(string rootPath) + { + if (rootPath != null) + { + rootPath.NotNullOrWhiteSpace(nameof(rootPath)); + + if (!rootPath.IsValidPath()) + { + throw new ArgumentException($"Invalid path '{rootPath}'", nameof(rootPath)); + } + } + + return + new FileLinkSettings( + (issue, values) => + { + values.Add("rootPath", rootPath); + + return this.builder(issue, values); + }); + } + } +} diff --git a/src/Cake.Issues/FileLinking/GitHubFileLinkSettingsBuilder.cs b/src/Cake.Issues/FileLinking/GitHubFileLinkSettingsBuilder.cs new file mode 100644 index 000000000..ef3b23d53 --- /dev/null +++ b/src/Cake.Issues/FileLinking/GitHubFileLinkSettingsBuilder.cs @@ -0,0 +1,102 @@ +namespace Cake.Issues.FileLinking +{ + using System; + + /// + /// Class for building settings for file links of files hosted on GitHub. + /// + internal class GitHubFileLinkSettingsBuilder + { + private readonly Uri repositoryUrl; + + /// + /// Initializes a new instance of the class. + /// + /// Full URL of the Git repository, + /// eg. https://github.com/cake-contrib/Cake.Issues. + internal GitHubFileLinkSettingsBuilder(Uri repositoryUrl) + { + repositoryUrl.NotNull(nameof(repositoryUrl)); + + this.repositoryUrl = repositoryUrl; + } + + /// + /// Returns settings to files on GitHub on a specific branch. + /// + /// Name of the branch. + /// Class for setting additional settings. + public FileLinkOptionalSettingsBuilder Branch(string branchName) + { + branchName.NotNullOrWhiteSpace(nameof(branchName)); + + return + new FileLinkOptionalSettingsBuilder( + (issue, values) => + { + issue.NotNull(nameof(issue)); + values.NotNull(nameof(values)); + + var fileLinkPattern = + this.repositoryUrl.Append( + "blob", + branchName, + values.GetValueOrDefault("rootPath", null), + GetFilePathPattern(issue)).ToString(); + + return new Uri(fileLinkPattern.ReplaceIssuePattern(issue)); + }); + } + + /// + /// Returns settings to files on GitHub on a specific commit. + /// + /// The commit id on which the file linking will be based on. + /// Class for setting additional settings. + public FileLinkOptionalSettingsBuilder Commit(string commitId) + { + commitId.NotNullOrWhiteSpace(nameof(commitId)); + + return + new FileLinkOptionalSettingsBuilder( + (issue, values) => + { + issue.NotNull(nameof(issue)); + values.NotNull(nameof(values)); + + var fileLinkPattern = + this.repositoryUrl.Append( + "blob", + commitId, + values.GetValueOrDefault("rootPath", null), + GetFilePathPattern(issue)).ToString(); + + return new Uri(fileLinkPattern.ReplaceIssuePattern(issue)); + }); + } + + /// + /// Returns the pattern for the file path and line information. + /// + /// Issue for which the pattern should be returned. + /// Pattern. + private static string GetFilePathPattern(IIssue issue) + { + issue.NotNull(nameof(issue)); + + var filePathPattern = "{FilePath}"; + + if (issue.Line.HasValue) + { + filePathPattern += "#L{Line}"; + } + + if (issue.EndLine.HasValue) + { + filePathPattern += "-L{EndLine}"; + } + + return filePathPattern; + } + } +} diff --git a/src/Cake.Issues/FileLinking/IDictionaryExtensions.cs b/src/Cake.Issues/FileLinking/IDictionaryExtensions.cs new file mode 100644 index 000000000..bc08a5638 --- /dev/null +++ b/src/Cake.Issues/FileLinking/IDictionaryExtensions.cs @@ -0,0 +1,29 @@ +namespace Cake.Issues.FileLinking +{ + using System.Collections.Generic; + + /// + /// Extensions for . + /// + internal static class IDictionaryExtensions + { + /// + /// Gets the value associated with a key or the default value. + /// + /// Type of the key in the dictionary. + /// Type of the value in the dictionary. + /// Dictionary to read the key from. + /// The key whose value to get. + /// Value to return if key does not exist. + /// The value associated with the key if it exists or . + public static TValue GetValueOrDefault( + this IDictionary dictionary, + TKey key, + TValue defaultValue) + { + dictionary.NotNull(nameof(dictionary)); + + return dictionary.TryGetValue(key, out var value) ? value : defaultValue; + } + } +} diff --git a/src/Cake.Issues/IIssueExtensions.cs b/src/Cake.Issues/IIssueExtensions.cs index a846ec126..22f26caf1 100644 --- a/src/Cake.Issues/IIssueExtensions.cs +++ b/src/Cake.Issues/IIssueExtensions.cs @@ -93,10 +93,10 @@ public static string FileName(this IIssue issue) /// Returns a string with all patterns replaced by the values of . /// /// Pattern whose values should be replaced. - /// The following patterns are supported: + /// The following tokens are supported: /// /// - /// Pattern + /// Token /// Description /// /// From e30188700a8b4691f876d13a508610849ce734d3 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Fri, 7 Aug 2020 09:12:19 +0200 Subject: [PATCH 28/31] Add alias for custom file link settings (#200) --- .../FileLinkSettingsTests.cs | 65 +++++++++++++++-- src/Cake.Issues/Aliases.FileLinking.cs | 72 +++++++++++++++++++ src/Cake.Issues/FileLinkSettings.cs | 31 ++++++++ 3 files changed, 162 insertions(+), 6 deletions(-) diff --git a/src/Cake.Issues.Tests/FileLinkSettingsTests.cs b/src/Cake.Issues.Tests/FileLinkSettingsTests.cs index acbbed283..a80847747 100644 --- a/src/Cake.Issues.Tests/FileLinkSettingsTests.cs +++ b/src/Cake.Issues.Tests/FileLinkSettingsTests.cs @@ -24,6 +24,64 @@ public void Should_Throw_If_Builder_Is_Null() } } + public sealed class TheForPatternMethod + { + [Fact] + public void Should_Throw_If_Pattern_Is_Null() + { + // Given + string pattern = null; + + // When + var result = Record.Exception(() => FileLinkSettings.ForPattern(pattern)); + + // Then + result.IsArgumentNullException("pattern"); + } + + [Fact] + public void Should_Throw_If_Pattern_Is_Empty() + { + // Given + var pattern = string.Empty; + + // When + var result = Record.Exception(() => FileLinkSettings.ForPattern(pattern)); + + // Then + result.IsArgumentOutOfRangeException("pattern"); + } + + [Fact] + public void Should_Throw_If_Pattern_Is_WhiteSpace() + { + // Given + var pattern = " "; + + // When + var result = Record.Exception(() => FileLinkSettings.ForPattern(pattern)); + + // Then + result.IsArgumentOutOfRangeException("pattern"); + } + } + + public sealed class TheForActionMethod + { + [Fact] + public void Should_Throw_If_Builder_Is_Null() + { + // Given + Func builder = null; + + // When + var result = Record.Exception(() => FileLinkSettings.ForAction(builder)); + + // Then + result.IsArgumentNullException("builder"); + } + } + public sealed class TheForGitHubMethod { [Fact] @@ -65,12 +123,7 @@ public void Should_Throw_If_Issue_Is_Null() IIssue issue = null; // When - var result = - Record.Exception(() => - FileLinkSettings - .ForGitHub(new Uri("https://github.com")) - .Branch("master") - .GetFileLink(issue)); + var result = Record.Exception(() => FileLinkSettings.ForPattern("foo").GetFileLink(issue)); // Then result.IsArgumentNullException("issue"); diff --git a/src/Cake.Issues/Aliases.FileLinking.cs b/src/Cake.Issues/Aliases.FileLinking.cs index b29edf204..ddb70f4f0 100644 --- a/src/Cake.Issues/Aliases.FileLinking.cs +++ b/src/Cake.Issues/Aliases.FileLinking.cs @@ -9,6 +9,78 @@ /// public static partial class Aliases { + /// + /// Gets an instance of the file link settings for linking to files + /// based on a custom pattern. + /// + /// The context. + /// Pattern of the file link. + /// See + /// for a list of tokens supported in the pattern. + /// Settings for linking files. + /// + /// Creates file link settings to an internal source hosting site: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] + public static FileLinkSettings IssueFileLinkSettings( + this ICakeContext context, + string pattern) + { + context.NotNull(nameof(context)); + pattern.NotNullOrWhiteSpace(nameof(pattern)); + + return FileLinkSettings.ForPattern(pattern); + } + + /// + /// Gets an instance of the file link settings for linking to files + /// based on a custom action. + /// + /// The context. + /// Callback called for building the file link. + /// File link settings. + /// Settings for linking files. + /// + /// Creates file link settings to an internal source hosting site with + /// parameters set dynamically, based on values of the issue: + /// + /// + /// { + /// var result = + /// new Uri("https://awesomesource/") + /// .Append(issue.FilePath()); + /// + /// if (issue.Line.HasValue) + /// { + /// result = result.Append("?line={issue.Line.Value}") + /// } + /// + /// return result; + /// }); + /// ]]> + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.FileLinkingCakeAliasCategory)] + public static FileLinkSettings IssueFileLinkSettings( + this ICakeContext context, + Func builder) + { + context.NotNull(nameof(context)); + builder.NotNull(nameof(builder)); + + return FileLinkSettings.ForAction(builder); + } + /// /// Gets an instance of the file link settings for linking files hosted on GitHub on a specific branch. /// diff --git a/src/Cake.Issues/FileLinkSettings.cs b/src/Cake.Issues/FileLinkSettings.cs index 7ec2e497e..75e60f370 100644 --- a/src/Cake.Issues/FileLinkSettings.cs +++ b/src/Cake.Issues/FileLinkSettings.cs @@ -35,6 +35,37 @@ public Uri GetFileLink(IIssue issue) return this.builder(issue, new Dictionary()); } + /// + /// Returns settings to link files based on a custom pattern. + /// + /// Pattern of the file link. + /// See + /// for a list of tokens supported in the pattern. + /// File link settings. + internal static FileLinkSettings ForPattern(string pattern) + { + pattern.NotNullOrWhiteSpace(nameof(pattern)); + + return + new FileLinkSettings( + (issue, values) => + { + return new Uri(pattern.ReplaceIssuePattern(issue)); + }); + } + + /// + /// Returns settings to link files based on a custom pattern. + /// + /// Callback called for building the file link. + /// File link settings. + internal static FileLinkSettings ForAction(Func builder) + { + builder.NotNull(nameof(builder)); + + return new FileLinkSettings((issue, values) => builder(issue)); + } + /// /// Returns builder class for settings for linking to files hosted in GitHub. /// From 57c90189162bba89934235e3224b9556ab77af29 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Mon, 10 Aug 2020 08:28:30 +0200 Subject: [PATCH 29/31] Make WithEnding public since it might be useful in other addins (#203) --- src/Cake.Issues/StringPathExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cake.Issues/StringPathExtensions.cs b/src/Cake.Issues/StringPathExtensions.cs index fbb7990f0..07ea8ff20 100644 --- a/src/Cake.Issues/StringPathExtensions.cs +++ b/src/Cake.Issues/StringPathExtensions.cs @@ -103,7 +103,7 @@ public static string NormalizePath(this string path) /// String to which should be added. /// String which should be added to . /// with the minimal concatenation of . - internal static string WithEnding(this string value, string ending) + public static string WithEnding(this string value, string ending) { if (value == null) { From 33cbc5d447599de2cdb597c386aba2475b801fe8 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Mon, 10 Aug 2020 09:52:06 +0200 Subject: [PATCH 30/31] Add LineRange extensions (#202) --- .../IIssueExtensionsTests.cs | 92 +++++++++++++++++++ src/Cake.Issues/IIssueExtensions.cs | 47 ++++++++++ 2 files changed, 139 insertions(+) diff --git a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs index 5cc79e071..ca488dbef 100644 --- a/src/Cake.Issues.Tests/IIssueExtensionsTests.cs +++ b/src/Cake.Issues.Tests/IIssueExtensionsTests.cs @@ -7,6 +7,98 @@ public sealed class IIssueExtensionsTests { + public sealed class TheLineRangeExtension + { + [Fact] + public void Should_Throw_If_Issue_Is_Null() + { + // Given + IIssue issue = null; + + // When + var result = Record.Exception(() => issue.LineRange()); + + // Then + result.IsArgumentNullException("issue"); + } + + [Theory] + [InlineData(null, null, null, null, "")] + [InlineData(10, null, null, null, "10")] + [InlineData(23, 42, null, null, "23-42")] + [InlineData(23, 42, 5, null, "23:5-42")] + [InlineData(23, 42, 5, 10, "23:5-42:10")] + public void Should_Return_Correct_LineRange( + int? startLine, + int? endLine, + int? startColumn, + int? endColumn, + string expectedLineRange) + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile("foo.ch", startLine, endLine, startColumn, endColumn) + .Create(); + + // When + var result = issue.LineRange(); + + // Then + result.ShouldBe(expectedLineRange); + } + } + + public sealed class TheLineRangeExtensionWithAddColumnParameter + { + [Fact] + public void Should_Throw_If_Issue_Is_Null() + { + // Given + IIssue issue = null; + + // When + var result = Record.Exception(() => issue.LineRange(false)); + + // Then + result.IsArgumentNullException("issue"); + } + + [Theory] + [InlineData(null, null, null, null, true, "")] + [InlineData(10, null, null, null, true, "10")] + [InlineData(23, 42, null, null, true, "23-42")] + [InlineData(23, 42, 5, null, true, "23:5-42")] + [InlineData(23, 42, 5, 10, true, "23:5-42:10")] + [InlineData(null, null, null, null, false, "")] + [InlineData(10, null, null, null, false, "10")] + [InlineData(23, 42, null, null, false, "23-42")] + [InlineData(23, 42, 5, null, false, "23-42")] + [InlineData(23, 42, 5, 10, false, "23-42")] + public void Should_Return_Correct_LineRange( + int? startLine, + int? endLine, + int? startColumn, + int? endColumn, + bool addColumnInformation, + string expectedLineRange) + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile("foo.ch", startLine, endLine, startColumn, endColumn) + .Create(); + + // When + var result = issue.LineRange(addColumnInformation); + + // Then + result.ShouldBe(expectedLineRange); + } + } + public sealed class TheProjectPathExtension { [Fact] diff --git a/src/Cake.Issues/IIssueExtensions.cs b/src/Cake.Issues/IIssueExtensions.cs index 22f26caf1..efd1710b5 100644 --- a/src/Cake.Issues/IIssueExtensions.cs +++ b/src/Cake.Issues/IIssueExtensions.cs @@ -7,6 +7,53 @@ /// public static class IIssueExtensions { + /// + /// Returns the line and column range in the format {Line}:{Column}-{EndLine}:{EndColumn}. + /// + /// Issue for which the line and column range should be returned. + /// Line and column range. + public static string LineRange(this IIssue issue) + { + issue.NotNull(nameof(issue)); + + return issue.LineRange(true); + } + + /// + /// Returns the line range in the format {Line}:{Column}-{EndLine}:{EndColumn}. + /// + /// Issue for which the line range should be returned. + /// Flag if column information should also be returned. + /// Line and column range. + public static string LineRange(this IIssue issue, bool addColumn) + { + issue.NotNull(nameof(issue)); + + string result = string.Empty; + + if (issue.Line.HasValue) + { + result += issue.Line.ToString(); + + if (addColumn && issue.Column.HasValue) + { + result += $":{issue.Column.Value}"; + } + + if (issue.EndLine.HasValue) + { + result += $"-{issue.EndLine.Value}"; + + if (addColumn && issue.EndColumn.HasValue) + { + result += $":{issue.EndColumn.Value}"; + } + } + } + + return result; + } + /// /// Gets the message of the issue in a specific format. /// If the message is not available in the specific format, the message in From d775b31f8abde811fc764acf06946963405aa1ab Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Fri, 14 Aug 2020 21:45:03 +0200 Subject: [PATCH 31/31] Make FileLinkSettings builder public. (#206) There are use cases where direct access to FileLinkSettings would be helpful (e.g. for test cases in addins). --- src/Cake.Issues/FileLinkSettings.cs | 34 +++++++++---------- .../AzureDevOpsFileLinkSettingsBuilder.cs | 2 +- .../FileLinkOptionalSettingsBuilder.cs | 2 +- .../GitHubFileLinkSettingsBuilder.cs | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Cake.Issues/FileLinkSettings.cs b/src/Cake.Issues/FileLinkSettings.cs index 75e60f370..c1c54fcc3 100644 --- a/src/Cake.Issues/FileLinkSettings.cs +++ b/src/Cake.Issues/FileLinkSettings.cs @@ -22,19 +22,6 @@ internal FileLinkSettings(Func, Uri> builder this.builder = builder; } - /// - /// Returns the URL to the file on the source code hosting system - /// for the issue . - /// - /// Issue for which the link should be returned. - /// URL to the file on the source code hosting system. - public Uri GetFileLink(IIssue issue) - { - issue.NotNull(nameof(issue)); - - return this.builder(issue, new Dictionary()); - } - /// /// Returns settings to link files based on a custom pattern. /// @@ -42,7 +29,7 @@ public Uri GetFileLink(IIssue issue) /// See /// for a list of tokens supported in the pattern. /// File link settings. - internal static FileLinkSettings ForPattern(string pattern) + public static FileLinkSettings ForPattern(string pattern) { pattern.NotNullOrWhiteSpace(nameof(pattern)); @@ -59,7 +46,7 @@ internal static FileLinkSettings ForPattern(string pattern) /// /// Callback called for building the file link. /// File link settings. - internal static FileLinkSettings ForAction(Func builder) + public static FileLinkSettings ForAction(Func builder) { builder.NotNull(nameof(builder)); @@ -72,7 +59,7 @@ internal static FileLinkSettings ForAction(Func builder) /// Full URL of the Git repository, /// eg. https://github.com/cake-contrib/Cake.Issues. /// Builder class for the settings. - internal static GitHubFileLinkSettingsBuilder ForGitHub(Uri repositoryUrl) + public static GitHubFileLinkSettingsBuilder ForGitHub(Uri repositoryUrl) { repositoryUrl.NotNull(nameof(repositoryUrl)); @@ -85,11 +72,24 @@ internal static GitHubFileLinkSettingsBuilder ForGitHub(Uri repositoryUrl) /// Full URL of the Git repository, /// e.g. https://dev.azure.com/myorganization/_git/myrepo. /// Builder class for the settings. - internal static AzureDevOpsFileLinkSettingsBuilder ForAzureDevOps(Uri repositoryUrl) + public static AzureDevOpsFileLinkSettingsBuilder ForAzureDevOps(Uri repositoryUrl) { repositoryUrl.NotNull(nameof(repositoryUrl)); return new AzureDevOpsFileLinkSettingsBuilder(repositoryUrl); } + + /// + /// Returns the URL to the file on the source code hosting system + /// for the issue . + /// + /// Issue for which the link should be returned. + /// URL to the file on the source code hosting system. + public Uri GetFileLink(IIssue issue) + { + issue.NotNull(nameof(issue)); + + return this.builder(issue, new Dictionary()); + } } } diff --git a/src/Cake.Issues/FileLinking/AzureDevOpsFileLinkSettingsBuilder.cs b/src/Cake.Issues/FileLinking/AzureDevOpsFileLinkSettingsBuilder.cs index 74e5a3f27..1351a7f58 100644 --- a/src/Cake.Issues/FileLinking/AzureDevOpsFileLinkSettingsBuilder.cs +++ b/src/Cake.Issues/FileLinking/AzureDevOpsFileLinkSettingsBuilder.cs @@ -6,7 +6,7 @@ /// /// Class for building settings for file links of files hosted on Azure DevOps. /// - internal class AzureDevOpsFileLinkSettingsBuilder + public class AzureDevOpsFileLinkSettingsBuilder { private readonly Uri repositoryUrl; diff --git a/src/Cake.Issues/FileLinking/FileLinkOptionalSettingsBuilder.cs b/src/Cake.Issues/FileLinking/FileLinkOptionalSettingsBuilder.cs index d193b9d03..f8a776144 100644 --- a/src/Cake.Issues/FileLinking/FileLinkOptionalSettingsBuilder.cs +++ b/src/Cake.Issues/FileLinking/FileLinkOptionalSettingsBuilder.cs @@ -6,7 +6,7 @@ /// /// Class containing builder for optional settings for linking to files. /// - internal class FileLinkOptionalSettingsBuilder : FileLinkSettings + public class FileLinkOptionalSettingsBuilder : FileLinkSettings { private readonly Func, Uri> builder; diff --git a/src/Cake.Issues/FileLinking/GitHubFileLinkSettingsBuilder.cs b/src/Cake.Issues/FileLinking/GitHubFileLinkSettingsBuilder.cs index ef3b23d53..c8a6f8ccc 100644 --- a/src/Cake.Issues/FileLinking/GitHubFileLinkSettingsBuilder.cs +++ b/src/Cake.Issues/FileLinking/GitHubFileLinkSettingsBuilder.cs @@ -5,7 +5,7 @@ /// /// Class for building settings for file links of files hosted on GitHub. /// - internal class GitHubFileLinkSettingsBuilder + public class GitHubFileLinkSettingsBuilder { private readonly Uri repositoryUrl;