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();
        }
Exemple #2
0
        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);
        }
Exemple #7
0
        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;
                }
            }
        }
Exemple #8
0
        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();
        }
Exemple #10
0
        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");
        }
Exemple #11
0
        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);
        }
Exemple #17
0
        /// <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);
        }
Exemple #19
0
        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();
            }
        }
Exemple #20
0
        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");
        }
Exemple #21
0
        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");
        }
Exemple #22
0
        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)
                       ));
        }
Exemple #24
0
        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();
        }
Exemple #25
0
        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();
        }