public void Ctor_FlowsAreNeverNull() { var testSubject = new SonarQubeIssue("issueKey", "file", "hash", "message", "module", "rule", true, SonarQubeIssueSeverity.Info, ValidTimestamp, ValidTimestamp, new IssueTextRange(123, 456, 7, 8), flows: null); testSubject.Flows.Should().BeEmpty(); }
public void GetSuppressedIssues_WhenProjectHasNoModulesAndIssueIsModuleLevelAndFound_ReturnsExpectedIssue() { // Arrange var sonarQubeIssue1 = new SonarQubeIssue(null, null, null, "message", "sqkey", "S1", true); var sonarQubeIssue2 = new SonarQubeIssue("/foo/bar.cs", "hash", 12, "message", "sqkey", "S2", true); SetupSolutionBinding(true, new List <SonarQubeIssue> { sonarQubeIssue1 }, new List <SonarQubeModule> { new SonarQubeModule("sqkey", "", "") }); var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqkey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); VerifyServiceGetIssues(Times.Exactly(1)); // issues should be fetched on creation // Act var matches = issuesProvider.GetSuppressedIssues("projectId", null); // Assert matches.Should().HaveCount(1); matches.First().RuleId.Should().Be("S1"); }
public void GetIssues_IssuesExists_DifferentSQProjectKey_NoMatches() { var issue1 = new SonarQubeIssue("file1", "hash1", 0, "message", "otherkey:otherkey:projectID1", SonarQubeIssueResolutionState.FalsePositive, "S101"); var issue2 = new SonarQubeIssue("folder1/file1", "hash2", 0, "message", "otherkey:otherkey:projectID2", SonarQubeIssueResolutionState.FalsePositive, "S102"); SetupSolutionBinding(isConnected: true, issues: new List <SonarQubeIssue> { issue1, issue2 }); var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqKey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); VerifyServiceGetIssues(Times.Exactly(1)); // issues should be fetched on creation // 1. SonarQube project key doesn't match -> no issues var matches = issuesProvider.GetSuppressedIssues("projectID1", "file1"); matches.Should().BeEmpty(); // 2. SonarQube project key doesn't match -> no issues matches = issuesProvider.GetSuppressedIssues("PROJECTID2", "folder1/file1"); matches.Should().BeEmpty(); VerifyServiceGetIssues(Times.Exactly(1)); // cached issues should be used }
public void GetIssues_ErrorInInitialFetchTask_IsSuppressed() { var issue1 = new SonarQubeIssue("folder1/file1", "hash1", 0, "message", "sqkey:sqkey:projectID1", SonarQubeIssueResolutionState.FalsePositive, "S101"); Func <IList <SonarQubeIssue> > serviceFetchIssuesTask = () => { InitialFetchWaitHandle.Set(); // signal so the test can continue throw new ApplicationException("dummy error from mock"); }; SetupSolutionBinding(isConnected: true, serviceFetchIssuesTask: serviceFetchIssuesTask); // 1. Create the issue provider // The initial fetch should be triggered, but not yet completed var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqkey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); // 2. Now request the issues - task completes with an error var matches = issuesProvider.GetSuppressedIssues("projectid1", "folder1/file1"); VerifyServiceGetIssues(Times.Once(), "sqkey"); matches.Should().BeEmpty(); // 3. Now fetch again - should not wait again, should not error matches = issuesProvider.GetSuppressedIssues("folder1/file1", "projectid1"); matches.Should().BeEmpty(); VerifyServiceGetIssues(Times.Once()); testLogger.AssertPartialOutputStrings("Checking for suppressions", "dummy error from mock"); }
public void GetIssues_IssuesExists_FiltersByFileAndProject() { var issue1 = new SonarQubeIssue("folder1/file1", "hash1", 0, "message", "sqkey:sqkey:projectID1", SonarQubeIssueResolutionState.FalsePositive, "S101"); var issue2 = new SonarQubeIssue("folder1/file1", "hash2", 0, "message", "sqkey:sqkey:projectID2", SonarQubeIssueResolutionState.WontFix, "S102"); var issue3 = new SonarQubeIssue("folder1/file1", "hash3", 0, "message", "sqkey:sqkey:projectID2", SonarQubeIssueResolutionState.Fixed, "S103"); var issue4 = new SonarQubeIssue("folder1/file1", "hash4", 0, "message", "sqkey:sqkey: projectID2", SonarQubeIssueResolutionState.WontFix, "S104"); var issue5 = new SonarQubeIssue("folder1/file1", "hash5", 0, "message", "sqkey:XXX:projectID2", SonarQubeIssueResolutionState.FalsePositive, "S105"); var issue6 = new SonarQubeIssue("folder1/file2", "hash6", 0, "message", "sqkey:sqkey:projectID1", SonarQubeIssueResolutionState.Unresolved, "S106"); var issue7 = new SonarQubeIssue("folder2/file1", "hash7", 0, "message", "sqkey:sqkey:projectID1", SonarQubeIssueResolutionState.Fixed, "S107"); var issue8 = new SonarQubeIssue("file1", "hash8", 0, "message", "sqkey:sqkey:projectID1", SonarQubeIssueResolutionState.FalsePositive, "S108"); var issue9 = new SonarQubeIssue("file1", "hash9", 0, "message", "sqkey:sqkey:projectID1xxx", SonarQubeIssueResolutionState.WontFix, "S109"); var issue10 = new SonarQubeIssue("file1", "hash10", 0, "message", "sqkey:sqkey:projectID", SonarQubeIssueResolutionState.Unresolved, "S110"); SetupSolutionBinding(isConnected: true, issues: new List <SonarQubeIssue> { issue1, issue2, issue3, issue4, issue5, issue6, issue7, issue8, issue9, issue1 }); var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqKey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); VerifyServiceGetIssues(Times.Exactly(1)); // issues should be fetched on creation // 1. Project id doesn't match -> no issues var matches = issuesProvider.GetSuppressedIssues("unrecognisedProjectId", "folder1/file1"); matches.Should().BeEmpty(); VerifyServiceGetIssues(Times.Exactly(1), "sqKey"); // cached issues should be used // 2. File id doesn't match -> no issues matches = issuesProvider.GetSuppressedIssues("projectID1", "folder1/filexxx"); matches.Should().BeEmpty(); // 3. File id and guid match -> issues returned matches = issuesProvider.GetSuppressedIssues("projectID1", "file1"); matches.Count().Should().Be(1); CheckExpectedIssueReturned("hash8", matches); // 4. File id and guid match, case-insensitive -> issues returned matches = issuesProvider.GetSuppressedIssues("PROJECTID2", "FOLDER1/FILE1"); matches.Count().Should().Be(2); CheckExpectedIssueReturned("hash2", matches); CheckExpectedIssueReturned("hash3", matches); VerifyServiceGetIssues(Times.Exactly(1)); }
public void Ctor_PropertiesAreSet() { var creationTimestamp = DateTimeOffset.Parse("2001-12-13T10:11:12+0000"); var lastUpdateTimestamp = DateTimeOffset.Parse("2020-01-02T13:14:15+0000"); var flows = new List <IssueFlow> { new IssueFlow(null), new IssueFlow(null) }; var testSubject = new SonarQubeIssue("issueKey", "file", "hash", "message", "module", "rule", true, SonarQubeIssueSeverity.Info, creationTimestamp, lastUpdateTimestamp, new IssueTextRange(123, 456, 7, 8), flows); testSubject.IssueKey.Should().Be("issueKey"); testSubject.FilePath.Should().Be("file"); testSubject.Hash.Should().Be("hash"); testSubject.Message.Should().Be("message"); testSubject.ModuleKey.Should().Be("module"); testSubject.RuleId.Should().Be("rule"); testSubject.IsResolved.Should().BeTrue(); testSubject.Severity.Should().Be(SonarQubeIssueSeverity.Info); testSubject.CreationTimestamp.Should().Be(creationTimestamp); testSubject.LastUpdateTimestamp.Should().Be(lastUpdateTimestamp); testSubject.TextRange.Should().BeEquivalentTo(new IssueTextRange(123, 456, 7, 8)); testSubject.Flows.Should().BeEquivalentTo(flows); }
private void GetValuesFromApi() { var lastResult = _sonarQubeApi.ExecuteRequest <IssueResult>(_metricUri); foreach (var issue in lastResult.Issues) { var sonarQubeIssue = new SonarQubeIssue { Severity = issue.Severity, Line = issue.Line, Message = issue.Message, Effort = issue.Effort, Type = issue.Type, ComponentId = issue.Component, SubProjectId = issue.SubProject }; _issues.Add(sonarQubeIssue); foreach (var sqissue in _issues) { var component = lastResult.Components.Where(c => c.Key == sqissue.ComponentId).FirstOrDefault(); sqissue.FileName = component.Name; component = lastResult.Components.Where(c => c.Key == sqissue.SubProjectId).FirstOrDefault(); sqissue.ProjectName = component.Name; } } }
public void GetSuppressedIssues_WhenProjectHasModulesAndIssueIsOnAFileAtRootLevel_FalseMatch() { // Same as previous test except that the SonarQube Project contains multiple modules // Arrange var sonarQubeIssue1 = new SonarQubeIssue("foo.cs", null, null, "message", "sqkey", "S1", true); var sonarQubeIssue2 = new SonarQubeIssue("toto/foo.cs", null, null, "message", "sqkey", "S2", true); SetupSolutionBinding(true, new List <SonarQubeIssue> { sonarQubeIssue1, sonarQubeIssue2 }, new List <SonarQubeModule> { new SonarQubeModule("sqkey", "", ""), new SonarQubeModule("sqkey:sqkey:guid", "", "src/bar/foo") }); var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqkey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); VerifyServiceGetIssues(Times.Exactly(1)); // issues should be fetched on creation // Act / Assert - same file name exists at multiple levels in the hierarchy // This is the False Match... var matches = issuesProvider.GetSuppressedIssues("", "C:\\AwesomeProject\\src\\bar\\foo\\foo.cs"); matches.Should().HaveCount(1); matches.First().RuleId.Should().Be("S1"); // ... and this is the correct one matches = issuesProvider.GetSuppressedIssues("", "C:\\AwesomeProject\\src\\bar\\foo.cs"); matches.Should().HaveCount(1); matches.First().RuleId.Should().Be("S1"); }
public void Ctor_TextRangeCanBeNull() { var testSubject = new SonarQubeIssue("issueKey", "file", "hash", "message", "module", "rule", true, SonarQubeIssueSeverity.Info, ValidTimestamp, ValidTimestamp, textRange: null, flows: null); testSubject.TextRange.Should().BeNull(); }
public void GetSuppressedIssues_WhenIssueIsFileLevel_ShouldMatchUsingCasingInsensitiveComparison() { // Arrange var sonarQubeIssue1 = new SonarQubeIssue("foo.CS", null, null, "message", "sqkey:sqkey:projectId", "S1", true); var sonarQubeIssue2 = new SonarQubeIssue("/foo/FOO.cs", null, null, "message", "sqkey:sqkey:projectId", "S2", true); SetupSolutionBinding(true, new List <SonarQubeIssue> { sonarQubeIssue1, sonarQubeIssue2 }, new List <SonarQubeModule> { new SonarQubeModule("sqkey:sqkey:projectId", "", "src/bar") }); var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqkey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); VerifyServiceGetIssues(Times.Exactly(1)); // issues should be fetched on creation // Act var matches = issuesProvider.GetSuppressedIssues("", "C:\\AWESOMEProject\\SRC\\bar\\FOO\\foo.cS"); // Assert matches.Should().HaveCount(1); matches.First().RuleId.Should().Be("S2"); }
public void GetSuppressedIssues_WhenIssueIsFileLevel_ShouldMatchOnLongestPath() { // Arrange var sonarQubeIssue1 = new SonarQubeIssue("foo.cs", null, null, "message", "sqkey:sqkey:projectId", "S1", true); var sonarQubeIssue2 = new SonarQubeIssue("/foo/foo.cs", null, null, "message", "sqkey:sqkey:projectId", "S2", true); SetupSolutionBinding(true, new List <SonarQubeIssue> { sonarQubeIssue1, sonarQubeIssue2 }, new List <SonarQubeModule> { new SonarQubeModule("sqkey:sqkey:projectId", "", "src/bar") }); var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqkey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); VerifyServiceGetIssues(Times.Exactly(1)); // issues should be fetched on creation // Act / Assert - #1 - Longest path is retrieved first var matches = issuesProvider.GetSuppressedIssues("", "C:\\AwesomeProject\\src\\bar\\foo\\foo.cs"); matches.Should().HaveCount(1); matches.First().RuleId.Should().Be("S2"); // Act / Assert - #2 - Shortest path matches = issuesProvider.GetSuppressedIssues("", "C:\\AwesomeProject\\src\\bar\\foo.cs"); matches.Should().HaveCount(1); matches.First().RuleId.Should().Be("S1"); }
public IAnalysisIssueVisualization Convert(SonarQubeIssue sonarQubeIssue) { var analysisIssue = ConvertToAnalysisIssue(sonarQubeIssue); var issueViz = issueVisualizationConverter.Convert(analysisIssue); CalculateLocalFilePaths(issueViz); return(issueViz); }
public async Task <IList <SonarQubeIssue> > GetSuppressedIssuesAsync(string key, CancellationToken token) { EnsureIsConnected(); var allIssuesResult = await this.sonarqubeClient.GetIssuesAsync(key, token); allIssuesResult.EnsureSuccess(); return(allIssuesResult.Value .Where(x => SonarQubeIssue.ParseResolutionState(x.Resolution) != SonarQubeIssueResolutionState.Unresolved) .Select(SonarQubeIssue.FromResponse) .ToList()); }
private static bool IsMatch(IFilterableIssue issue, SonarQubeIssue serverIssue) { if (!StringComparer.OrdinalIgnoreCase.Equals(issue.RuleId, serverIssue.RuleId)) { return(false); } if (!issue.StartLine.HasValue) // i.e. file-level issue { return(serverIssue.TextRange == null); } // Non-file level issue return(issue.StartLine == serverIssue.TextRange?.StartLine || StringComparer.Ordinal.Equals(issue.LineHash, serverIssue.Hash)); }
public void GetIssues_ErrorFetchingOnTimerElapsed_IsSuppressed() { // Tests that the timer trigger that causes the data to be refetched won't propagate errors // if the GetIssues call throws. var issue1 = new SonarQubeIssue("folder1/file1", "hash1", 0, "message", "sqkey:sqkey:projectId", SonarQubeIssueResolutionState.FalsePositive, "S101"); SetupSolutionBinding(isConnected: true, issues: new List <SonarQubeIssue> { issue1 }); // 1. Create the issue provider and call GetIssues to make sure the issues are cached var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqkey", mockTimerFactory.Object, testLogger); var matches = issuesProvider.GetSuppressedIssues("projectId", "folder1/file1"); VerifyServiceGetIssues(Times.Once()); matches.Count().Should().Be(1); testLogger.AssertPartialOutputStrings("Checking for suppressions", "1"); // 2. Configure service to throw, then execute the fetch trigger int fetchCallCount = 0; testLogger.Reset(); Func <IList <SonarQubeIssue> > serviceFetchIssuesTask = () => { fetchCallCount++; throw new ApplicationException("dummy error from mock"); }; SetupSolutionBinding(isConnected: true, serviceFetchIssuesTask: serviceFetchIssuesTask); RaiseTimerElapsed(DateTime.UtcNow); // 3. Fetch issues again - should used cached issues matches = issuesProvider.GetSuppressedIssues("projectId", "folder1/file1"); VerifyServiceGetIssues(Times.Exactly(2)); matches.Count().Should().Be(1); fetchCallCount.Should().Be(1); VerifyTimerStart(Times.Exactly(1)); // once, on construction testLogger.AssertPartialOutputStrings("Checking for suppressions", "dummy error from mock"); }
public void GetIssues_IssuesNotYetFetch_WaitsForIssuesToBeFetched() { var issue1 = new SonarQubeIssue("folder1/file1", "hash1", 0, "message", "sqkey:sqkey:projectID1", SonarQubeIssueResolutionState.FalsePositive, "S101"); int callbackCount = 0; bool callbackCompleted = false; Func <IList <SonarQubeIssue> > serviceFetchIssuesTask = () => { callbackCount++; InitialFetchWaitHandle.Set(); // signal so the test can continue Thread.Sleep(Debugger.IsAttached ? 5000 : 500); callbackCompleted = true; return(new List <SonarQubeIssue> { issue1 }); }; SetupSolutionBinding(isConnected: true, serviceFetchIssuesTask: serviceFetchIssuesTask); // 1. Create the issue provider // The initial fetch should be triggered, but not yet completed var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqKey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); // 2. Now request the issues - should wait until the issues have been retrieved var matches = issuesProvider.GetSuppressedIssues("projectid1", "folder1/file1"); VerifyServiceGetIssues(Times.Once(), "sqKey"); callbackCount.Should().Be(1); callbackCompleted.Should().BeTrue(); matches.Count().Should().Be(1); CheckExpectedIssueReturned("hash1", matches); // 3. Now fetch again - should not wait again matches = issuesProvider.GetSuppressedIssues("folder1/file1", "projectid1"); VerifyServiceGetIssues(Times.Once()); callbackCount.Should().Be(1); }
/// <summary> /// Constructor. /// </summary> /// <param name="service">SonarQube source from which this issue originates.</param> /// <param name="issue">SonarQube issue.</param> public ErrorListItem(Uri baseUrl, SonarQubeIssue issue) : this() { var errorCode = GetErrorCode(issue.Rule); ProjectName = string.Empty; FileName = GetFileName(issue.Component); // Visual Studio expects line to be 0-based rather than 1-based like SonarQube. // Reference: https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.shell.tablemanager.standardtablekeynames.line?view=visualstudiosdk-2017 Line = issue.Line - 1; Message = GetErrorMessage(issue.Message); ErrorCode = errorCode; ErrorCodeToolTip = GetErrorCodeToolTip(errorCode); ErrorCategory = GetErrorCategory(issue.Severity, issue.Type); Severity = GetErrorSeverity(issue.Severity, issue.Type); HelpLink = GetHelpLink(baseUrl, issue.Rule); }
private string ProcessKey(Dictionary <string, string> keyToPath, SonarQubeIssue issue) { // File-level issues have a file path which is relative to their modules. // Note that relative paths coming from SonarQube/SonarCloud always use '/' as path delimiter // so we need to normalize them to '\' in order to match the implementation of LiveIssue.cs // 1 - Find the relative path of the module to the root string moduleToRootRelativePath; keyToPath.TryGetValue(issue.ModuleKey, out moduleToRootRelativePath); // 2 - Append the file relative path and normalize delimiters var filePathRelativeToRoot = moduleToRootRelativePath != null ? moduleToRootRelativePath + "\\" : string.Empty; filePathRelativeToRoot += NormalizeSonarQubePath(issue.FilePath); return(filePathRelativeToRoot); }
public void GetSuppressedIssues_WhenProjectHasModulesAndIssueIsFileLevelAndIsNotFound_ReturnsNoIssue() { // Arrange var sonarQubeIssue1 = new SonarQubeIssue("\\foo\\foo.cs", null, null, "message", "sqkey:sqkey:projectId", "S1", true); var sonarQubeIssue2 = new SonarQubeIssue("/foo/foo.cs", null, null, "message", "sqkey:sqkey:projectId", "S2", true); var sonarQubeIssue3 = new SonarQubeIssue("foo\\foo.cs", null, null, "message", "sqkey:sqkey:projectId", "S3", true); var sonarQubeIssue4 = new SonarQubeIssue("foo/foo.cs", null, null, "message", "sqkey:sqkey:projectId", "S4", true); var sonarQubeIssue5 = new SonarQubeIssue("bar/bar.cs", null, null, "message", "sqkey:sqkey:projectId", "S5", true); SetupSolutionBinding(true, new List <SonarQubeIssue> { sonarQubeIssue1, sonarQubeIssue2, sonarQubeIssue3, sonarQubeIssue4, sonarQubeIssue5 }, new List <SonarQubeModule> { new SonarQubeModule("sqkey", "", ""), new SonarQubeModule("sqkey:sqkey:projectId", "", "src/bar") }); var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqkey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); VerifyServiceGetIssues(Times.Exactly(1)); // issues should be fetched on creation // We're deliberately faking SonarQube returning paths with \ instead of / which // the code should handle, but with an assertion since it means the format returned // by SonarQube has changed. using (new AssertIgnoreScope()) { // Act / Assert - #1 - file extension is not right var matches = issuesProvider.GetSuppressedIssues("guid doesn't matter", "C:\\AwesomeProject\\src\\bar\\foo\\foo.vb"); matches.Should().BeEmpty(); // Act / Assert - #2 - path is not normalized while comparison is strict for delimiters matches = issuesProvider.GetSuppressedIssues("guid doesn't matter", "C:/AwesomeProject/src/bar/foo/foo.cs"); matches.Should().BeEmpty(); // Act / Assert - #3 - current file is one level up compared to remote file matches = issuesProvider.GetSuppressedIssues("guid doesn't matter", "C:\\AwesomeProject\\src\\bar\\foo.cs"); matches.Should().BeEmpty(); } }
public void GetSuppressedIssues_WhenProjectHasModulesAndIssueIsFileLevelAndIsFound_ReturnsExpectedIssue() { // Arrange var sonarQubeIssue1 = new SonarQubeIssue("\\foo\\foo.cs", null, null, "message", "sqkey:sqkey:projectId", "S1", true); var sonarQubeIssue2 = new SonarQubeIssue("/foo/foo.cs", null, null, "message", "sqkey:sqkey:projectId", "S2", true); var sonarQubeIssue3 = new SonarQubeIssue("foo\\FOO.cs", null, null, "message", "sqkey:sqkey:projectId", "S3", true); var sonarQubeIssue4 = new SonarQubeIssue("FOO/foo.cs", null, null, "message", "sqkey:sqkey:projectId", "S4", true); var sonarQubeIssue5 = new SonarQubeIssue("bar/bar.cs", null, null, "message", "sqkey:sqkey:projectId", "S5", true); SetupSolutionBinding(true, new List <SonarQubeIssue> { sonarQubeIssue1, sonarQubeIssue2, sonarQubeIssue3, sonarQubeIssue4, sonarQubeIssue5 }, new List <SonarQubeModule> { new SonarQubeModule("sqkey", "", ""), new SonarQubeModule("sqkey:sqkey:projectId", "", "src/bar") }); var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqkey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); VerifyServiceGetIssues(Times.Exactly(1)); // issues should be fetched on creation // Act IEnumerable <SonarQubeIssue> matches; // We're deliberately faking SonarQube returning paths with \ instead of / which // the code should handle, but with an assertion since it means the format returned // by SonarQube has changed. using (new AssertIgnoreScope()) { matches = issuesProvider.GetSuppressedIssues("guid doesn't matter", "C:\\AwesomeProject\\src\\bar\\foo\\foo.cs"); } // Assert matches.Should().HaveCount(4); matches.Should().OnlyContain(x => x.RuleId != "S5"); }
public void GetSuppressedIssues_WhenProjectHasNoModuleAndIssueIsOnAFileAtRootLevelWithNoModules_FalseMatch() { // On this test we are in an unlikely situation of having an issue suppressed only on a file(1) which is associated // with the root module and whose name also exists deeper in the file system hierarchy. // (1) If some issue was suppressed for the file deeper in the hierarchy it wouldn't find the wrong match as we // test from the longest matching to the shortest. // Arrange var sonarQubeIssue1 = new SonarQubeIssue("foo.cs", null, null, "message", "sqkey", "S1", true); var sonarQubeIssue2 = new SonarQubeIssue("toto/foo.cs", null, null, "message", "sqkey", "S2", true); SetupSolutionBinding(true, new List <SonarQubeIssue> { sonarQubeIssue1, sonarQubeIssue2 }, new List <SonarQubeModule> { new SonarQubeModule("sqkey", "", "") }); var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqkey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); VerifyServiceGetIssues(Times.Exactly(1)); // issues should be fetched on creation // Act / Assert - same file name exists at multiple levels in the hierarchy // This is the False Match... var matches = issuesProvider.GetSuppressedIssues("", "C:\\AwesomeProject\\src\\bar\\foo\\foo.cs"); matches.Should().HaveCount(1); matches.First().RuleId.Should().Be("S1"); // ... and this is the correct one matches = issuesProvider.GetSuppressedIssues("", "C:\\AwesomeProject\\src\\bar\\foo.cs"); matches.Should().HaveCount(1); matches.First().RuleId.Should().Be("S1"); }
public void GetSuppressedIssues_WhenProjectHasModulesAndIssueIsModuleLevelAndIsNotFound_ReturnsNoIssue() { // Arrange var sonarQubeIssue1 = new SonarQubeIssue(null, null, null, "message", "sqkey:sqkey:projectId2", "S1", true); var sonarQubeIssue2 = new SonarQubeIssue("/foo/bar.cs", "hash", 123, "message", "sqkey:sqkey:projectId", "S2", true); var sonarQubeIssue3 = new SonarQubeIssue("/foo/bar.cs", "hash", 12, "message", "FOOBAR", "S3", true); SetupSolutionBinding(true, new List <SonarQubeIssue> { sonarQubeIssue1, sonarQubeIssue2, sonarQubeIssue3 }); var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqkey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); VerifyServiceGetIssues(Times.Exactly(1)); // issues should be fetched on creation // Act var matches = issuesProvider.GetSuppressedIssues("FOOBAR", null); // Assert matches.Should().BeEmpty(); }
private IAnalysisIssueBase ConvertToAnalysisIssue(SonarQubeIssue sonarQubeIssue) { if (sonarQubeIssue.TextRange == null) { throw new ArgumentNullException(nameof(sonarQubeIssue.TextRange)); } return(new TaintIssue( sonarQubeIssue.IssueKey, sonarQubeIssue.FilePath, sonarQubeIssue.RuleId, sonarQubeIssue.Message, sonarQubeIssue.TextRange.StartLine, sonarQubeIssue.TextRange.EndLine, sonarQubeIssue.TextRange.StartOffset, sonarQubeIssue.TextRange.EndOffset, sonarQubeIssue.Hash, Convert(sonarQubeIssue.Severity), sonarQubeIssue.CreationTimestamp, sonarQubeIssue.LastUpdateTimestamp, Convert(sonarQubeIssue.Flows) )); }
public void GetSuppressedIssues_WhenProjectHasNoModulesAndIssueIsOnAFileWhoseRelativePathExistsMultipleTimes_FalseMatch() { // Arrange var sonarQubeIssue1 = new SonarQubeIssue("aaa/foo.cs", null, null, "message", "sqkey", "S1", true); var sonarQubeIssue2 = new SonarQubeIssue("toto/foo.cs", null, null, "message", "sqkey", "S2", true); SetupSolutionBinding(true, new List <SonarQubeIssue> { sonarQubeIssue1, sonarQubeIssue2 }, new List <SonarQubeModule> { new SonarQubeModule("sqkey", "", "") }); var issuesProvider = new SonarQubeIssuesProvider(mockSqService.Object, "sqkey", mockTimerFactory.Object, testLogger); WaitForInitialFetchTaskToStart(); VerifyServiceGetIssues(Times.Exactly(1)); // issues should be fetched on creation // Act / Assert // #1 - matches the correct file... var matches = issuesProvider.GetSuppressedIssues("", "C:\\aaa\\foo.cs"); matches.Should().HaveCount(1); matches.First().RuleId.Should().Be("S1"); // #2 - ...but also matches a wrong file deeper in the hierarchy with the same suffix... matches = issuesProvider.GetSuppressedIssues("", "C:\\bar\\bar2\\aaa\\foo.cs"); matches.Should().HaveCount(1); matches.First().RuleId.Should().Be("S1"); // #3 - ... but no match for files upper in the hierarchy. matches = issuesProvider.GetSuppressedIssues("", "C:\\foo.cs"); matches.Should().BeEmpty(); }
private static bool ExistedComment(List <GitPullRequestCommentThread> threads, SonarQubeIssue issue) { var matchFilePath = threads.Any(p => p.ThreadContext != null && p.ThreadContext.FilePath.Contains(issue.FilePath)); var matchCommentPosition = threads.Any( p => p.ThreadContext != null && p.ThreadContext.RightFileStart != null && p.ThreadContext.RightFileStart.Line == issue.Line && p.ThreadContext.RightFileStart.Offset == issue.TextRange.StartOffset); return(matchFilePath && matchCommentPosition); }
private static void CheckExpectedIssueReturned(string expectedHash, IEnumerable <SonarQubeIssue> actualIssues) { SonarQubeIssue match = actualIssues.FirstOrDefault(i => i.Hash.Equals(expectedHash, StringComparison.InvariantCultureIgnoreCase)); match.Should().NotBeNull(); }