@Test
public void testProjectIdWithWebUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("http://example.com/diaspora/diaspora-client");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithWebUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("http://example.com/diaspora/diaspora-client");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

public void init(File projectBaseDir) {
    initGitBaseDir(projectBaseDir);
    gitLabAPI = GitLabAPI.connect(config.url(), config.userToken()).setIgnoreCertificateErrors(config.ignoreCertificate());
    if (config.isProxyConnectionEnabled()) {
        gitLabAPI.setProxy(config.getHttpProxy());
    }
    try {
        gitLabProject = getGitLabProject();
        Paged<GitLabCommitDiff> paged = gitLabAPI.getGitLabAPICommits().getCommitDiffs(gitLabProject.getId(), config.commitSHA(), null);
        List<GitLabCommitDiff> commitDiffs = new ArrayList<>();
        do {
            if (paged.getResults() != null) {
                commitDiffs.addAll(paged.getResults());
            }
        } while ((paged = paged.nextPage()) != null);
        patchPositionMappingByFile = mapPatchPositionsToLines(commitDiffs);
    } catch (IOException e) {
        throw new IllegalStateException("Unable to perform GitLab WS operation", e);
    }
}

public void init(File projectBaseDir) {
    initGitBaseDir(projectBaseDir);
    gitLabAPI = GitLabAPI.connect(config.url(), config.userToken()).setIgnoreCertificateErrors(config.ignoreCertificate());
    if (config.isProxyConnectionEnabled()) {
        gitLabAPI.setProxy(config.getHttpProxy());
    }
    try {
        gitLabProject = getGitLabProject();
        commitCommentPerRevision = getCommitCommentsPerRevision(config.commitSHA());
        patchPositionByFile = getPatchPositionsToLineMapping(config.commitSHA());
    } catch (IOException e) {
        throw new IllegalStateException("Unable to perform GitLab WS operation", e);
    }
}

@Test
public void testProjectIdWithHttpUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("http://example.com/diaspora/diaspora-client.git");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithHttpUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("http://example.com/diaspora/diaspora-client.git");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithId() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("123");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithId() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("123");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithName() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("Diaspora / Diaspora Client");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithName() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("Diaspora / Diaspora Client");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithSshUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("git@example.com:diaspora/diaspora-client.git");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithSshUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("git@example.com:diaspora/diaspora-client.git");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithPath() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("diaspora/diaspora-client");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithPath() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("diaspora/diaspora-client");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}


@Test
public void testProject() {
    Assertions.assertThat(config.isEnabled()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_COMMIT_SHA, "3");
    Assertions.assertThat(config.commitSHA()).isEqualTo("3");
    Assertions.assertThat(config.isEnabled()).isTrue();
    Assertions.assertThat(config.commentNoIssue()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_COMMENT_NO_ISSUE, "true");
    Assertions.assertThat(config.commentNoIssue()).isTrue();
    Assertions.assertThat(config.tryReportIssuesInline()).isTrue();
    settings.setProperty(GitLabPlugin.GITLAB_DISABLE_INLINE_COMMENTS, "true");
    Assertions.assertThat(config.tryReportIssuesInline()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_PROJECT_ID, "123");
    Assertions.assertThat(config.projectId()).isEqualTo("123");
    Assertions.assertThat(config.ignoreFileNotModified()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_IGNORE_FILE, "true");
    Assertions.assertThat(config.ignoreFileNotModified()).isTrue();
    settings.setProperty(GitLabPlugin.GITLAB_REF_NAME, "123");
    Assertions.assertThat(config.refName()).isEqualTo("123");
    Assertions.assertThat(config.onlyIssueFromCommitFile()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_ONLY_ISSUE_FROM_COMMIT_FILE, "true");
    Assertions.assertThat(config.onlyIssueFromCommitFile()).isTrue();
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.PENDING);
    settings.setProperty(GitLabPlugin.GITLAB_BUILD_INIT_STATE, BuildInitState.RUNNING.getMeaning());
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.RUNNING);
    settings.setProperty(GitLabPlugin.GITLAB_BUILD_INIT_STATE, "toto");
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.PENDING);
    Assertions.assertThat(config.disableGlobalComment()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_DISABLE_GLOBAL_COMMENT, "true");
    Assertions.assertThat(config.disableGlobalComment()).isTrue();
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.COMMIT_STATUS);
    settings.setProperty(GitLabPlugin.GITLAB_STATUS_NOTIFICATION_MODE, StatusNotificationsMode.EXIT_CODE.getMeaning());
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.EXIT_CODE);
    settings.setProperty(GitLabPlugin.GITLAB_STATUS_NOTIFICATION_MODE, "toto");
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.COMMIT_STATUS);
}

@Test
public void testProject() {
    Assertions.assertThat(config.isEnabled()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_COMMIT_SHA, "3");
    Assertions.assertThat(config.commitSHA()).containsExactly("3");
    settings.setProperty(GitLabPlugin.GITLAB_COMMIT_SHA, "3,4,5");
    Assertions.assertThat(config.commitSHA()).containsExactly("3", "4", "5");
    Assertions.assertThat(config.isEnabled()).isTrue();
    Assertions.assertThat(config.commentNoIssue()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_COMMENT_NO_ISSUE, "true");
    Assertions.assertThat(config.commentNoIssue()).isTrue();
    Assertions.assertThat(config.tryReportIssuesInline()).isTrue();
    settings.setProperty(GitLabPlugin.GITLAB_DISABLE_INLINE_COMMENTS, "true");
    Assertions.assertThat(config.tryReportIssuesInline()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_PROJECT_ID, "123");
    Assertions.assertThat(config.projectId()).isEqualTo("123");
    settings.setProperty(GitLabPlugin.GITLAB_REF_NAME, "123");
    Assertions.assertThat(config.refName()).isEqualTo("123");
    Assertions.assertThat(config.onlyIssueFromCommitFile()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_ONLY_ISSUE_FROM_COMMIT_FILE, "true");
    Assertions.assertThat(config.onlyIssueFromCommitFile()).isTrue();
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.PENDING);
    settings.setProperty(GitLabPlugin.GITLAB_BUILD_INIT_STATE, BuildInitState.RUNNING.getMeaning());
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.RUNNING);
    settings.setProperty(GitLabPlugin.GITLAB_BUILD_INIT_STATE, "toto");
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.PENDING);
    Assertions.assertThat(config.disableGlobalComment()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_DISABLE_GLOBAL_COMMENT, "true");
    Assertions.assertThat(config.disableGlobalComment()).isTrue();
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.COMMIT_STATUS);
    settings.setProperty(GitLabPlugin.GITLAB_STATUS_NOTIFICATION_MODE, StatusNotificationsMode.EXIT_CODE.getMeaning());
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.EXIT_CODE);
    settings.setProperty(GitLabPlugin.GITLAB_STATUS_NOTIFICATION_MODE, "toto");
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.COMMIT_STATUS);
    Assertions.assertThat(config.globalTemplate()).isNull();
    settings.setProperty(GitLabPlugin.GITLAB_GLOBAL_TEMPLATE, "# Test");
    Assertions.assertThat(config.globalTemplate()).isEqualTo("# Test");
    Assertions.assertThat(config.inlineTemplate()).isNull();
    settings.setProperty(GitLabPlugin.GITLAB_INLINE_TEMPLATE, "# Test");
    Assertions.assertThat(config.inlineTemplate()).isEqualTo("# Test");
    Assertions.assertThat(config.pingUser()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_PING_USER, "true");
    Assertions.assertThat(config.pingUser()).isTrue();
    Assertions.assertThat(config.uniqueIssuePerInline()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_UNIQUE_ISSUE_PER_INLINE, "true");
    Assertions.assertThat(config.uniqueIssuePerInline()).isTrue();
}

public boolean pingUser() {
    return settings.getBoolean(GitLabPlugin.GITLAB_PING_USER);
}


@Test
public void testCommitAnalysisWithNewBlockerAndCriticalIssues() {
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.CRITICAL, true, "msg1");
    when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    PostJobIssue lineNotVisible = newMockedIssue("foo:src/Foo.php", inputFile1, 2, Severity.BLOCKER, true, "msg2");
    when(commitFacade.getGitLabUrl(inputFile1, 2)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L2");
    when(context.issues()).thenReturn(Arrays.<PostJobIssue>asList(newIssue, lineNotVisible));
    when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    verify(commitFacade).createOrUpdateSonarQubeStatus("failed", "SonarQube reported 2 issues, with 1 critical and 1 blocker");
}

@Test
public void testCommitAnalysisWithNewBlockerAndCriticalIssues() {
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.CRITICAL, true, "msg1");
    when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    PostJobIssue lineNotVisible = newMockedIssue("foo:src/Foo.php", inputFile1, 2, Severity.BLOCKER, true, "msg2");
    when(commitFacade.getGitLabUrl(inputFile1, 2)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L2");
    when(context.issues()).thenReturn(Arrays.<PostJobIssue>asList(newIssue, lineNotVisible));
    when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    verify(commitFacade).createOrUpdateSonarQubeStatus("failed", "SonarQube reported 2 issues, with 1 blocker (fail) and 1 critical (fail)");
}

@Override
public void execute(PostJobContext context) {
    GlobalReport report = new GlobalReport(gitLabPluginConfiguration, markDownUtils);
    try {
        LOG.info("Find a {} new issues", getStreamPostJobIssue(context.issues()).count());
        Map<InputFile, Map<Integer, StringBuilder>> commentsToBeAddedByLine = processIssues(report, context.issues());
        updateReviewComments(commentsToBeAddedByLine);
        if (report.hasNewIssue() || gitLabPluginConfiguration.commentNoIssue()) {
            commitFacade.addGlobalComment(report.formatForMarkdown());
        }
        commitFacade.createOrUpdateSonarQubeStatus(report.getStatus(), report.getStatusDescription());
    } catch (Exception e) {
        String msg = "SonarQube failed to complete the review of this commit";
        LOG.error(msg, e);
        commitFacade.createOrUpdateSonarQubeStatus("failed", msg + ": " + e.getMessage());
    }
}

@Override
public void execute(PostJobContext context) {
    GlobalReport report = new GlobalReport(gitLabPluginConfiguration, markDownUtils);
    try {
        Map<InputFile, Map<Integer, StringBuilder>> commentsToBeAddedByLine = processIssues(report, context.issues());
        updateReviewComments(commentsToBeAddedByLine);
        if (!gitLabPluginConfiguration.disableGlobalComment() && (report.hasNewIssue() || gitLabPluginConfiguration.commentNoIssue())) {
            commitFacade.addGlobalComment(report.formatForMarkdown());
        }
        String status = report.getStatus();
        String statusDescription = report.getStatusDescription();
        String message = String.format("Report status=%s, desc=%s", report.getStatus(), report.getStatusDescription());
        StatusNotificationsMode i = gitLabPluginConfiguration.statusNotificationsMode();
        if (i == StatusNotificationsMode.COMMIT_STATUS) {
            LOG.info(message);
            commitFacade.createOrUpdateSonarQubeStatus(status, statusDescription);
        } else if (i == StatusNotificationsMode.EXIT_CODE) {
            if ("failed".equals(status)) {
                throw MessageException.of(message);
            } else {
                LOG.info(message);
            }
        }
    } catch (MessageException e) {
        throw e;
    } catch (Exception e) {
        String msg = "SonarQube failed to complete the review of this commit";
        LOG.error(msg, e);
        StatusNotificationsMode i = gitLabPluginConfiguration.statusNotificationsMode();
        if (i == StatusNotificationsMode.COMMIT_STATUS) {
            commitFacade.createOrUpdateSonarQubeStatus("failed", msg + ": " + e.getMessage());
        }
    }
}

@Test
public void testCommitAnalysisWithNewCriticalIssues() {
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.CRITICAL, true, "msg1");
    when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    when(context.issues()).thenReturn(Collections.singletonList(newIssue));
    when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    verify(commitFacade).createOrUpdateSonarQubeStatus("failed", "SonarQube reported 1 issue, with 1 critical");
}

@Test
public void testCommitAnalysisWithNewCriticalIssues() {
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.CRITICAL, true, "msg1");
    when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    when(context.issues()).thenReturn(Collections.singletonList(newIssue));
    when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    verify(commitFacade).createOrUpdateSonarQubeStatus("failed", "SonarQube reported 1 issue, with 1 critical (fail)");
}

@Test
public void testCommitAnalysisWithNewIssuesOnly() {
    settings.setProperty(GitLabPlugin.GITLAB_ONLY_ISSUE_FROM_COMMIT_FILE, true);
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, true, "msg1");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    PostJobIssue lineNotVisible = newMockedIssue("foo:src/Foo.php", inputFile1, 2, Severity.BLOCKER, true, "msg2");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 2)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L2");
    DefaultInputFile inputFile2 = new DefaultInputFile("foo", "src/Foo2.php");
    PostJobIssue fileNotInPR = newMockedIssue("foo:src/Foo2.php", inputFile2, 1, Severity.BLOCKER, true, "msg3");
    PostJobIssue notNewIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, false, "msg");
    PostJobIssue issueOnDir = newMockedIssue("foo:src", Severity.BLOCKER, true, "msg4");
    PostJobIssue issueOnProject = newMockedIssue("foo", Severity.BLOCKER, true, "msg");
    PostJobIssue globalIssue = newMockedIssue("foo:src/Foo.php", inputFile1, null, Severity.BLOCKER, true, "msg5");
    Mockito.when(context.issues()).thenReturn(Arrays.<PostJobIssue>asList(newIssue, globalIssue, issueOnProject, issueOnDir, fileNotInPR, lineNotVisible, notNewIssue));
    Mockito.when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    Mockito.when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("SonarQube analysis reported 5 issues"));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("* :no_entry: 5 blocker"));
    Mockito.verify(commitFacade).addGlobalComment(AdditionalMatchers.not(Mockito.contains("1. [Project")));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("1. :no_entry: [msg2](http://gitlab/blob/abc123/src/Foo.php#L2) [:blue_book:](http://myserver/coding_rules#rule_key=repo%3Arule)"));
    Mockito.verify(commitFacade).createOrUpdateSonarQubeStatus("failed", "SonarQube reported 5 issues, with 5 blocker");
}

@Test
public void testCommitAnalysisWithNewIssuesOnly() {
    settings.setProperty(GitLabPlugin.GITLAB_ONLY_ISSUE_FROM_COMMIT_FILE, true);
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, true, "msg1");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    PostJobIssue lineNotVisible = newMockedIssue("foo:src/Foo.php", inputFile1, 2, Severity.BLOCKER, true, "msg2");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 2)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L2");
    DefaultInputFile inputFile2 = new DefaultInputFile("foo", "src/Foo2.php");
    PostJobIssue fileNotInPR = newMockedIssue("foo:src/Foo2.php", inputFile2, 1, Severity.BLOCKER, true, "msg3");
    PostJobIssue notNewIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, false, "msg");
    PostJobIssue issueOnDir = newMockedIssue("foo:src", Severity.BLOCKER, true, "msg4");
    PostJobIssue issueOnProject = newMockedIssue("foo", Severity.BLOCKER, true, "msg");
    PostJobIssue globalIssue = newMockedIssue("foo:src/Foo.php", inputFile1, null, Severity.BLOCKER, true, "msg5");
    Mockito.when(context.issues()).thenReturn(Arrays.<PostJobIssue>asList(newIssue, globalIssue, issueOnProject, issueOnDir, fileNotInPR, lineNotVisible, notNewIssue));
    Mockito.when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    Mockito.when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("SonarQube analysis reported 5 issues"));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("* :no_entry: 5 blocker"));
    Mockito.verify(commitFacade).addGlobalComment(AdditionalMatchers.not(Mockito.contains("1. [Project")));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("1. :no_entry: [msg2](http://gitlab/blob/abc123/src/Foo.php#L2) [:blue_book:](http://myserver/coding_rules#rule_key=repo%3Arule)"));
    Mockito.verify(commitFacade).createOrUpdateSonarQubeStatus("failed", "SonarQube reported 5 issues, with 5 blocker (fail)");
}

@Test
public void testCommitAnalysisWithNewIssuesNoBlockerNorCritical() {
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.MAJOR, true, "msg1");
    when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    when(context.issues()).thenReturn(Collections.singletonList(newIssue));
    when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    verify(commitFacade).createOrUpdateSonarQubeStatus("success", "SonarQube reported 1 issue, no criticals or blockers");
}

@Test
public void testCommitAnalysisWithNewIssuesNoBlockerNorCritical() {
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.MAJOR, true, "msg1");
    when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    when(context.issues()).thenReturn(Collections.singletonList(newIssue));
    when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    verify(commitFacade).createOrUpdateSonarQubeStatus("success", "SonarQube reported 1 issue, with 1 major");
}

@Test
public void testCommitAnalysisWithNewIssues() {
    settings.setProperty(GitLabPlugin.GITLAB_ONLY_ISSUE_FROM_COMMIT_FILE, false);
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, true, "msg1");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    PostJobIssue lineNotVisible = newMockedIssue("foo:src/Foo.php", inputFile1, 2, Severity.BLOCKER, true, "msg2");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 2)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L2");
    DefaultInputFile inputFile2 = new DefaultInputFile("foo", "src/Foo2.php");
    PostJobIssue fileNotInPR = newMockedIssue("foo:src/Foo2.php", inputFile2, 1, Severity.BLOCKER, true, "msg3");
    PostJobIssue notNewIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, false, "msg");
    PostJobIssue issueOnDir = newMockedIssue("foo:src", Severity.BLOCKER, true, "msg4");
    PostJobIssue issueOnProject = newMockedIssue("foo", Severity.BLOCKER, true, "msg");
    PostJobIssue globalIssue = newMockedIssue("foo:src/Foo.php", inputFile1, null, Severity.BLOCKER, true, "msg5");
    Mockito.when(context.issues()).thenReturn(Arrays.<PostJobIssue>asList(newIssue, globalIssue, issueOnProject, issueOnDir, fileNotInPR, lineNotVisible, notNewIssue));
    Mockito.when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    Mockito.when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("SonarQube analysis reported 6 issues"));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("* :no_entry: 6 blocker"));
    Mockito.verify(commitFacade).addGlobalComment(AdditionalMatchers.not(Mockito.contains("1. [Project")));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("1. :no_entry: [msg2](http://gitlab/blob/abc123/src/Foo.php#L2) [:blue_book:](http://myserver/coding_rules#rule_key=repo%3Arule)"));
    Mockito.verify(commitFacade).createOrUpdateSonarQubeStatus("failed", "SonarQube reported 6 issues, with 6 blocker");
}

@Test
public void testCommitAnalysisWithNewIssues() {
    settings.setProperty(GitLabPlugin.GITLAB_ONLY_ISSUE_FROM_COMMIT_FILE, false);
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, true, "msg1");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    PostJobIssue lineNotVisible = newMockedIssue("foo:src/Foo.php", inputFile1, 2, Severity.BLOCKER, true, "msg2");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 2)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L2");
    DefaultInputFile inputFile2 = new DefaultInputFile("foo", "src/Foo2.php");
    PostJobIssue fileNotInPR = newMockedIssue("foo:src/Foo2.php", inputFile2, 1, Severity.BLOCKER, true, "msg3");
    PostJobIssue notNewIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, false, "msg");
    PostJobIssue issueOnDir = newMockedIssue("foo:src", Severity.BLOCKER, true, "msg4");
    PostJobIssue issueOnProject = newMockedIssue("foo", Severity.BLOCKER, true, "msg");
    PostJobIssue globalIssue = newMockedIssue("foo:src/Foo.php", inputFile1, null, Severity.BLOCKER, true, "msg5");
    Mockito.when(context.issues()).thenReturn(Arrays.<PostJobIssue>asList(newIssue, globalIssue, issueOnProject, issueOnDir, fileNotInPR, lineNotVisible, notNewIssue));
    Mockito.when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    Mockito.when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("SonarQube analysis reported 6 issues"));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("* :no_entry: 6 blocker"));
    Mockito.verify(commitFacade).addGlobalComment(AdditionalMatchers.not(Mockito.contains("1. [Project")));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("1. :no_entry: [msg2](http://gitlab/blob/abc123/src/Foo.php#L2) [:blue_book:](http://myserver/coding_rules#rule_key=repo%3Arule)"));
    Mockito.verify(commitFacade).createOrUpdateSonarQubeStatus("failed", "SonarQube reported 6 issues, with 6 blocker (fail)");
}


@Test
public void testProject() {
    Assertions.assertThat(config.isEnabled()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_COMMIT_SHA, "3");
    Assertions.assertThat(config.commitSHA()).isEqualTo("3");
    Assertions.assertThat(config.isEnabled()).isTrue();
    Assertions.assertThat(config.commentNoIssue()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_COMMENT_NO_ISSUE, "true");
    Assertions.assertThat(config.commentNoIssue()).isTrue();
    Assertions.assertThat(config.tryReportIssuesInline()).isTrue();
    settings.setProperty(GitLabPlugin.GITLAB_DISABLE_INLINE_COMMENTS, "true");
    Assertions.assertThat(config.tryReportIssuesInline()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_PROJECT_ID, "123");
    Assertions.assertThat(config.projectId()).isEqualTo("123");
    settings.setProperty(GitLabPlugin.GITLAB_REF_NAME, "123");
    Assertions.assertThat(config.refName()).isEqualTo("123");
    Assertions.assertThat(config.onlyIssueFromCommitFile()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_ONLY_ISSUE_FROM_COMMIT_FILE, "true");
    Assertions.assertThat(config.onlyIssueFromCommitFile()).isTrue();
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.PENDING);
    settings.setProperty(GitLabPlugin.GITLAB_BUILD_INIT_STATE, BuildInitState.RUNNING.getMeaning());
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.RUNNING);
    settings.setProperty(GitLabPlugin.GITLAB_BUILD_INIT_STATE, "toto");
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.PENDING);
    Assertions.assertThat(config.disableGlobalComment()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_DISABLE_GLOBAL_COMMENT, "true");
    Assertions.assertThat(config.disableGlobalComment()).isTrue();
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.COMMIT_STATUS);
    settings.setProperty(GitLabPlugin.GITLAB_STATUS_NOTIFICATION_MODE, StatusNotificationsMode.EXIT_CODE.getMeaning());
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.EXIT_CODE);
    settings.setProperty(GitLabPlugin.GITLAB_STATUS_NOTIFICATION_MODE, "toto");
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.COMMIT_STATUS);
    Assertions.assertThat(config.globalTemplate()).isNull();
    settings.setProperty(GitLabPlugin.GITLAB_GLOBAL_TEMPLATE, "# Test");
    Assertions.assertThat(config.globalTemplate()).isEqualTo("# Test");
}

public boolean ignoreFileNotModified() {
    return settings.getBoolean(GitLabPlugin.GITLAB_IGNORE_FILE);
}


@Test
public void testGlobalComment() throws IOException {
    GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
    when(gitLabPluginConfiguration.commitSHA()).thenReturn(Collections.singletonList("1"));
    when(gitLabPluginConfiguration.refName()).thenReturn("master");
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    GitLabAPI gitLabAPI = mock(GitLabAPI.class);
    facade.setGitLabAPI(gitLabAPI);
    GitLabAPICommits gitLabAPICommits = mock(GitLabAPICommits.class);
    when(gitLabAPICommits.postCommitComments("1", "1", "pending", "master", null, null)).thenReturn(null);
    when(gitLabAPI.getGitLabAPICommits()).thenReturn(gitLabAPICommits);
    GitLabProject gitLabProject = mock(GitLabProject.class);
    when(gitLabProject.getId()).thenReturn(1);
    facade.setGitLabProject(gitLabProject);
    facade.addGlobalComment("nothing");
    verify(gitLabAPICommits).postCommitComments(1, "1", "nothing", null, null, null);
}

@Test
public void testGlobalComment() throws IOException {
    GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
    when(gitLabPluginConfiguration.commitSHA()).thenReturn("1");
    when(gitLabPluginConfiguration.refName()).thenReturn("master");
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    GitLabAPI gitLabAPI = mock(GitLabAPI.class);
    facade.setGitLabAPI(gitLabAPI);
    GitLabAPICommits gitLabAPICommits = mock(GitLabAPICommits.class);
    when(gitLabAPICommits.postCommitComments("1", "1", "pending", "master", null, null)).thenReturn(null);
    when(gitLabAPI.getGitLabAPICommits()).thenReturn(gitLabAPICommits);
    GitLabProject gitLabProject = mock(GitLabProject.class);
    when(gitLabProject.getId()).thenReturn(1);
    facade.setGitLabProject(gitLabProject);
    facade.addGlobalComment("nothing");
    verify(gitLabAPICommits).postCommitComments(1, "1", "nothing", null, null, null);
}

public void addGlobalComment(String comment) {
    try {
        gitLabAPI.getGitLabAPICommits().postCommitComments(gitLabProject.getId(), getFirstCommitSHA(), comment, null, null, null);
    } catch (IOException e) {
        throw new IllegalStateException("Unable to comment the commit", e);
    }
}

public void addGlobalComment(String comment) {
    try {
        gitLabAPI.getGitLabAPICommits().postCommitComments(gitLabProject.getId(), config.commitSHA(), comment, null, null, null);
    } catch (IOException e) {
        throw new IllegalStateException("Unable to comment the commit", e);
    }
}

@Test
public void testReviewComment() throws IOException {
    GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
    when(gitLabPluginConfiguration.commitSHA()).thenReturn(Collections.singletonList("1"));
    when(gitLabPluginConfiguration.refName()).thenReturn("master");
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    File gitBasedir = temp.newFolder();
    facade.setGitBaseDir(gitBasedir);
    GitLabAPI gitLabAPI = mock(GitLabAPI.class);
    facade.setGitLabAPI(gitLabAPI);
    GitLabAPICommits gitLabAPICommits = mock(GitLabAPICommits.class);
    when(gitLabAPICommits.postCommitComments("1", "1", "pending", "master", null, null)).thenReturn(null);
    when(gitLabAPI.getGitLabAPICommits()).thenReturn(gitLabAPICommits);
    GitLabProject gitLabProject = mock(GitLabProject.class);
    when(gitLabProject.getId()).thenReturn(1);
    facade.setGitLabProject(gitLabProject);
    InputFile inputFile = mock(InputFile.class);
    when(inputFile.file()).thenReturn(new File(gitBasedir, "src/main/Foo.java"));
    facade.createOrUpdateReviewComment(null, inputFile, 5, "nothing");
    verify(gitLabAPICommits).postCommitComments(1, "1", "nothing", "src/main/Foo.java", 5, "new");
}

@Test
public void testReviewComment() throws IOException {
    GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
    when(gitLabPluginConfiguration.commitSHA()).thenReturn("1");
    when(gitLabPluginConfiguration.refName()).thenReturn("master");
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    File gitBasedir = temp.newFolder();
    facade.setGitBaseDir(gitBasedir);
    GitLabAPI gitLabAPI = mock(GitLabAPI.class);
    facade.setGitLabAPI(gitLabAPI);
    GitLabAPICommits gitLabAPICommits = mock(GitLabAPICommits.class);
    when(gitLabAPICommits.postCommitComments("1", "1", "pending", "master", null, null)).thenReturn(null);
    when(gitLabAPI.getGitLabAPICommits()).thenReturn(gitLabAPICommits);
    GitLabProject gitLabProject = mock(GitLabProject.class);
    when(gitLabProject.getId()).thenReturn(1);
    facade.setGitLabProject(gitLabProject);
    InputFile inputFile = mock(InputFile.class);
    when(inputFile.file()).thenReturn(new File(gitBasedir, "src/main/Foo.java"));
    facade.createOrUpdateReviewComment(inputFile, 5, "nothing");
    verify(gitLabAPICommits).postCommitComments(1, "1", "nothing", "src/main/Foo.java", 5, "new");
}

public void createOrUpdateReviewComment(String revision, InputFile inputFile, Integer line, String body) {
    String fullPath = getPath(inputFile);
    try {
        gitLabAPI.getGitLabAPICommits().postCommitComments(gitLabProject.getId(), revision != null ? revision : getFirstCommitSHA(), body, fullPath, line, "new");
    } catch (IOException e) {
        throw new IllegalStateException("Unable to create or update review comment in file " + fullPath + " at line " + line, e);
    }
}

public void createOrUpdateReviewComment(InputFile inputFile, Integer line, String body) {
    String fullPath = getPath(inputFile);
    try {
        gitLabAPI.getGitLabAPICommits().postCommitComments(gitLabProject.getId(), config.commitSHA(), body, fullPath, line, "new");
    } catch (IOException e) {
        throw new IllegalStateException("Unable to create or update review comment in file " + fullPath + " at line " + line, e);
    }
}

@Test
public void testPatchLineMapping_no_newline_at_the_end() throws IOException {
    CommitFacade facade = new CommitFacade(mock(GitLabPluginConfiguration.class));
    Set<CommitFacade.Line> patchLocationMapping = facade.getPositionsFromPatch("@@ -1 +0,0 @@\n-<fake/>\n\\ No newline at end of file");
    assertThat(patchLocationMapping).isEmpty();
}

@Test
public void testPatchLineMapping_no_newline_at_the_end() throws IOException {
    Set<Integer> patchLocationMapping = new HashSet<>();
    CommitFacade.processPatch(patchLocationMapping, "@@ -1 +0,0 @@\n-<fake/>\n\\ No newline at end of file");
    assertThat(patchLocationMapping).isEmpty();
}

static void processPatch(Set<Integer> patchLocationMapping, String patch) throws IOException {
    int currentLine = -1;
    for (String line : IOUtils.readLines(new StringReader(patch))) {
        if (line.startsWith("@")) {
            Matcher matcher = PATCH_PATTERN.matcher(line);
            if (!matcher.matches()) {
                throw new IllegalStateException("Unable to parse patch line " + line + "\nFull patch: \n" + patch);
            }
            currentLine = Integer.parseInt(matcher.group(1));
        } else if (line.startsWith("-")) {
        } else if (line.startsWith("+") || line.startsWith(" ")) {
            patchLocationMapping.add(currentLine);
            currentLine++;
        } else if (line.startsWith("\\")) {
        }
    }
}

@Test
public void testStatusFailed() throws IOException {
    GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
    when(gitLabPluginConfiguration.commitSHA()).thenReturn(Collections.singletonList("1"));
    when(gitLabPluginConfiguration.refName()).thenReturn("master");
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    GitLabAPI gitLabAPI = mock(GitLabAPI.class);
    facade.setGitLabAPI(gitLabAPI);
    GitLabAPICommits gitLabAPICommits = mock(GitLabAPICommits.class);
    when(gitLabAPICommits.postCommitStatus(1, "1", "pending", "master", "sonarqube", null, "nothing")).thenThrow(new IOException());
    when(gitLabAPI.getGitLabAPICommits()).thenReturn(gitLabAPICommits);
    GitLabProject gitLabProject = mock(GitLabProject.class);
    when(gitLabProject.getId()).thenReturn(1);
    facade.setGitLabProject(gitLabProject);
    facade.createOrUpdateSonarQubeStatus("pending", "nothing");
}

@Test
public void testStatusFailed() throws IOException {
    GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
    when(gitLabPluginConfiguration.commitSHA()).thenReturn("1");
    when(gitLabPluginConfiguration.refName()).thenReturn("master");
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    GitLabAPI gitLabAPI = mock(GitLabAPI.class);
    facade.setGitLabAPI(gitLabAPI);
    GitLabAPICommits gitLabAPICommits = mock(GitLabAPICommits.class);
    when(gitLabAPICommits.postCommitStatus(1, "1", "pending", "master", "sonarqube", null, "nothing")).thenThrow(new IOException());
    when(gitLabAPI.getGitLabAPICommits()).thenReturn(gitLabAPICommits);
    GitLabProject gitLabProject = mock(GitLabProject.class);
    when(gitLabProject.getId()).thenReturn(1);
    facade.setGitLabProject(gitLabProject);
    facade.createOrUpdateSonarQubeStatus("pending", "nothing");
}

public void createOrUpdateSonarQubeStatus(String status, String statusDescription) {
    try {
        gitLabAPI.getGitLabAPICommits().postCommitStatus(gitLabProject.getId(), getFirstCommitSHA(), status, config.refName(), COMMIT_CONTEXT, null, statusDescription);
    } catch (IOException e) {
        if (e.getMessage() != null && e.getMessage().contains("Cannot transition status")) {
            LOG.debug("Transition status is already {}", status);
        } else {
            LOG.error("Unable to update commit status", e);
        }
    }
}

public void createOrUpdateSonarQubeStatus(String status, String statusDescription) {
    try {
        gitLabAPI.getGitLabAPICommits().postCommitStatus(gitLabProject.getId(), config.commitSHA(), status, config.refName(), COMMIT_CONTEXT, null, statusDescription);
    } catch (IOException e) {
        if (e.getMessage() != null && e.getMessage().contains("Cannot transition status")) {
            LOG.debug("Transition status is already {}", status);
        } else {
            LOG.error("Unable to update commit status", e);
        }
    }
}

@Test
public void testPatchLineMapping_some_deleted_lines() throws IOException {
    CommitFacade facade = new CommitFacade(mock(GitLabPluginConfiguration.class));
    Set<CommitFacade.Line> patchLocationMapping = facade.getPositionsFromPatch("@@ -17,9 +17,6 @@\n  * along with this program; if not, write to the Free Software Foundation,\n  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n  */\n-/**\n- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.\n- */\n @ParametersAreNonnullByDefault\n package org.sonar.plugins.core.charts;\n ");
    assertThat(patchLocationMapping).isEmpty();
}

@Test
public void testPatchLineMapping_some_deleted_lines() throws IOException {
    Set<Integer> patchLocationMapping = new HashSet<>();
    CommitFacade.processPatch(patchLocationMapping, "@@ -17,9 +17,6 @@\n  * along with this program; if not, write to the Free Software Foundation,\n  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n  */\n-/**\n- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.\n- */\n @ParametersAreNonnullByDefault\n package org.sonar.plugins.core.charts;\n ");
    assertThat(patchLocationMapping).containsOnly(17, 18, 19, 20, 21, 22);
}

@Test
public void testGetGitLabUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
    when(gitLabPluginConfiguration.commitSHA()).thenReturn(Collections.singletonList("abc123"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.setGitBaseDir(gitBasedir);
    GitLabProject gitLabProject = mock(GitLabProject.class);
    when(gitLabProject.getWebUrl()).thenReturn("https://gitLab.com/gaby/test");
    facade.setGitLabProject(gitLabProject);
    InputPath inputPath = mock(InputPath.class);
    when(inputPath.file()).thenReturn(new File(gitBasedir, "src/main/Foo.java"));
    assertThat(facade.getGitLabUrl(null, inputPath, 10)).isEqualTo("https://gitLab.com/gaby/test/blob/abc123/src/main/Foo.java#L10");
}

@Test
public void testGetGitLabUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
    when(gitLabPluginConfiguration.commitSHA()).thenReturn("abc123");
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.setGitBaseDir(gitBasedir);
    GitLabProject gitLabProject = mock(GitLabProject.class);
    when(gitLabProject.getWebUrl()).thenReturn("https://gitLab.com/gaby/test");
    facade.setGitLabProject(gitLabProject);
    InputPath inputPath = mock(InputPath.class);
    when(inputPath.file()).thenReturn(new File(gitBasedir, "src/main/Foo.java"));
    assertThat(facade.getGitLabUrl(inputPath, 10)).isEqualTo("https://gitLab.com/gaby/test/blob/abc123/src/main/Foo.java#L10");
}

@CheckForNull
public String getGitLabUrl(@Nullable String revision, @Nullable InputComponent inputComponent, @Nullable Integer issueLine) {
    if (inputComponent instanceof InputPath) {
        String path = getPath((InputPath) inputComponent);
        return gitLabProject.getWebUrl() + "/blob/" + (revision != null ? revision : getFirstCommitSHA()) + "/" + path + (issueLine != null ? ("#L" + issueLine) : "");
    }
    return null;
}

@CheckForNull
public String getGitLabUrl(@Nullable InputComponent inputComponent, @Nullable Integer issueLine) {
    if (inputComponent instanceof InputPath) {
        String path = getPath((InputPath) inputComponent);
        return gitLabProject.getWebUrl() + "/blob/" + config.commitSHA() + "/" + path + (issueLine != null ? ("#L" + issueLine) : "");
    }
    return null;
}

@Test
public void testPatchLineMapping_some_added_lines() throws IOException {
    CommitFacade facade = new CommitFacade(mock(GitLabPluginConfiguration.class));
    Set<CommitFacade.Line> patchLocationMapping = facade.getPositionsFromPatch("@@ -24,9 +24,9 @@\n /**\n  * A plugin is a group of extensions. See org.sonar.api.Extension interface to browse\n  * available extension points.\n- *
\n  *
The manifest property Plugin-Class must declare the name of the implementation class.\n  * It is automatically set by sonar-packaging-maven-plugin when building plugins.
\n+ *
Implementation must declare a public constructor with no-parameters.
\n  *\n  * @see org.sonar.api.Extension\n  * @since 1.10");
    System.out.println(patchLocationMapping);
    assertThat(patchLocationMapping).containsOnly(new CommitFacade.Line(29, " *
Implementation must declare a public constructor with no-parameters.
"));
}

@Test
public void testPatchLineMapping_some_added_lines() throws IOException {
    Set<Integer> patchLocationMapping = new HashSet<>();
    CommitFacade.processPatch(patchLocationMapping, "@@ -24,9 +24,9 @@\n /**\n  * A plugin is a group of extensions. See org.sonar.api.Extension interface to browse\n  * available extension points.\n- *
\n  *
The manifest property Plugin-Class must declare the name of the implementation class.\n  * It is automatically set by sonar-packaging-maven-plugin when building plugins.
\n+ *
Implementation must declare a public constructor with no-parameters.
\n  *\n  * @see org.sonar.api.Extension\n  * @since 1.10");
    System.out.println(patchLocationMapping);
    assertThat(patchLocationMapping).containsOnly(32, 24, 25, 26, 27, 28, 29, 30, 31);
}

@Override
public boolean equals(Object o) {
    if (this == o) {
        return true;
    }
    if (o == null || getClass() != o.getClass()) {
        return false;
    }
    Line line = (Line) o;
    return Objects.equals(number, line.number) && Objects.equals(content, line.content);
}

@Test
public void testStatusSuccess() throws IOException {
    GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
    when(gitLabPluginConfiguration.commitSHA()).thenReturn(Collections.singletonList("1"));
    when(gitLabPluginConfiguration.refName()).thenReturn("master");
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    GitLabAPI gitLabAPI = mock(GitLabAPI.class);
    facade.setGitLabAPI(gitLabAPI);
    GitLabAPICommits gitLabAPICommits = mock(GitLabAPICommits.class);
    when(gitLabAPICommits.postCommitStatus(1, "1", "pending", "master", "sonarqube", "server", "")).thenReturn(null);
    when(gitLabAPI.getGitLabAPICommits()).thenReturn(gitLabAPICommits);
    GitLabProject gitLabProject = mock(GitLabProject.class);
    when(gitLabProject.getId()).thenReturn(1);
    facade.setGitLabProject(gitLabProject);
    facade.createOrUpdateSonarQubeStatus("pending", "nothing");
    verify(gitLabAPICommits).postCommitStatus(1, "1", "pending", "master", "sonarqube", null, "nothing");
}

@Test
public void testStatusSuccess() throws IOException {
    GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
    when(gitLabPluginConfiguration.commitSHA()).thenReturn("1");
    when(gitLabPluginConfiguration.refName()).thenReturn("master");
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    GitLabAPI gitLabAPI = mock(GitLabAPI.class);
    facade.setGitLabAPI(gitLabAPI);
    GitLabAPICommits gitLabAPICommits = mock(GitLabAPICommits.class);
    when(gitLabAPICommits.postCommitStatus(1, "1", "pending", "master", "sonarqube", "server", "")).thenReturn(null);
    when(gitLabAPI.getGitLabAPICommits()).thenReturn(gitLabAPICommits);
    GitLabProject gitLabProject = mock(GitLabProject.class);
    when(gitLabProject.getId()).thenReturn(1);
    facade.setGitLabProject(gitLabProject);
    facade.createOrUpdateSonarQubeStatus("pending", "nothing");
    verify(gitLabAPICommits).postCommitStatus(1, "1", "pending", "master", "sonarqube", null, "nothing");
}


@Test
public void testProjectIdWithWebUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("http://example.com/diaspora/diaspora-client");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithWebUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("http://example.com/diaspora/diaspora-client");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

public void init(File projectBaseDir) {
    initGitBaseDir(projectBaseDir);
    gitLabAPI = GitLabAPI.connect(config.url(), config.userToken()).setIgnoreCertificateErrors(config.ignoreCertificate());
    if (config.isProxyConnectionEnabled()) {
        gitLabAPI.setProxy(config.getHttpProxy());
    }
    try {
        gitLabProject = getGitLabProject();
        commitCommentPerRevision = getCommitCommentsPerRevision(config.commitSHA());
        patchPositionByFile = getPatchPositionsToLineMapping(config.commitSHA());
    } catch (IOException e) {
        throw new IllegalStateException("Unable to perform GitLab WS operation", e);
    }
}

public void init(File projectBaseDir) {
    initGitBaseDir(projectBaseDir);
    gitLabAPI = GitLabAPI.connect(config.url(), config.userToken()).setIgnoreCertificateErrors(config.ignoreCertificate());
    if (config.isProxyConnectionEnabled()) {
        gitLabAPI.setProxy(config.getHttpProxy());
    }
    try {
        gitLabProject = getGitLabProject();
        Paged<GitLabCommitDiff> paged = gitLabAPI.getGitLabAPICommits().getCommitDiffs(gitLabProject.getId(), config.commitSHA(), null);
        List<GitLabCommitDiff> commitDiffs = new ArrayList<>();
        do {
            if (paged.getResults() != null) {
                commitDiffs.addAll(paged.getResults());
            }
        } while ((paged = paged.nextPage()) != null);
        patchPositionMappingByFile = mapPatchPositionsToLines(commitDiffs);
    } catch (IOException e) {
        throw new IllegalStateException("Unable to perform GitLab WS operation", e);
    }
}

@Test
public void testProjectIdWithHttpUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("http://example.com/diaspora/diaspora-client.git");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithHttpUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("http://example.com/diaspora/diaspora-client.git");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithId() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("123");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithId() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("123");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithName() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("Diaspora / Diaspora Client");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithName() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("Diaspora / Diaspora Client");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithSshUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("git@example.com:diaspora/diaspora-client.git");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithSshUrl() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("git@example.com:diaspora/diaspora-client.git");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithPath() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("diaspora/diaspora-client");
    gitlab.enqueue(new MockResponse().setResponseCode(404));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}

@Test
public void testProjectIdWithPath() throws Exception {
    File gitBasedir = temp.newFolder();
    when(gitLabPluginConfiguration.projectId()).thenReturn("diaspora/diaspora-client");
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[{\n" + "    \"id\": 123,\n" + "    \"description\": null,\n" + "    \"default_branch\": \"master\",\n" + "    \"visibility\": \"private\",\n" + "    \"ssh_url_to_repo\": \"git@example.com:diaspora/diaspora-client.git\",\n" + "    \"http_url_to_repo\": \"http://example.com/diaspora/diaspora-client.git\",\n" + "    \"web_url\": \"http://example.com/diaspora/diaspora-client\",\n" + "\t\"name\": \"Diaspora Client\",\n" + "    \"name_with_namespace\": \"Diaspora / Diaspora Client\",\n" + "    \"path\": \"diaspora-client\",\n" + "    \"path_with_namespace\": \"diaspora/diaspora-client\"\n" + "}]"));
    gitlab.enqueue(new MockResponse().setResponseCode(200).setBody("[]"));
    CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
    facade.init(gitBasedir);
}


@Test
public void testProject() {
    Assertions.assertThat(config.isEnabled()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_COMMIT_SHA, "3");
    Assertions.assertThat(config.commitSHA()).containsExactly("3");
    settings.setProperty(GitLabPlugin.GITLAB_COMMIT_SHA, "3,4,5");
    Assertions.assertThat(config.commitSHA()).containsExactly("3", "4", "5");
    Assertions.assertThat(config.isEnabled()).isTrue();
    Assertions.assertThat(config.commentNoIssue()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_COMMENT_NO_ISSUE, "true");
    Assertions.assertThat(config.commentNoIssue()).isTrue();
    Assertions.assertThat(config.tryReportIssuesInline()).isTrue();
    settings.setProperty(GitLabPlugin.GITLAB_DISABLE_INLINE_COMMENTS, "true");
    Assertions.assertThat(config.tryReportIssuesInline()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_PROJECT_ID, "123");
    Assertions.assertThat(config.projectId()).isEqualTo("123");
    settings.setProperty(GitLabPlugin.GITLAB_REF_NAME, "123");
    Assertions.assertThat(config.refName()).isEqualTo("123");
    Assertions.assertThat(config.onlyIssueFromCommitFile()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_ONLY_ISSUE_FROM_COMMIT_FILE, "true");
    Assertions.assertThat(config.onlyIssueFromCommitFile()).isTrue();
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.PENDING);
    settings.setProperty(GitLabPlugin.GITLAB_BUILD_INIT_STATE, BuildInitState.RUNNING.getMeaning());
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.RUNNING);
    settings.setProperty(GitLabPlugin.GITLAB_BUILD_INIT_STATE, "toto");
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.PENDING);
    Assertions.assertThat(config.disableGlobalComment()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_DISABLE_GLOBAL_COMMENT, "true");
    Assertions.assertThat(config.disableGlobalComment()).isTrue();
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.COMMIT_STATUS);
    settings.setProperty(GitLabPlugin.GITLAB_STATUS_NOTIFICATION_MODE, StatusNotificationsMode.EXIT_CODE.getMeaning());
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.EXIT_CODE);
    settings.setProperty(GitLabPlugin.GITLAB_STATUS_NOTIFICATION_MODE, "toto");
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.COMMIT_STATUS);
    Assertions.assertThat(config.globalTemplate()).isNull();
    settings.setProperty(GitLabPlugin.GITLAB_GLOBAL_TEMPLATE, "# Test");
    Assertions.assertThat(config.globalTemplate()).isEqualTo("# Test");
    Assertions.assertThat(config.inlineTemplate()).isNull();
    settings.setProperty(GitLabPlugin.GITLAB_INLINE_TEMPLATE, "# Test");
    Assertions.assertThat(config.inlineTemplate()).isEqualTo("# Test");
    Assertions.assertThat(config.pingUser()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_PING_USER, "true");
    Assertions.assertThat(config.pingUser()).isTrue();
    Assertions.assertThat(config.uniqueIssuePerInline()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_UNIQUE_ISSUE_PER_INLINE, "true");
    Assertions.assertThat(config.uniqueIssuePerInline()).isTrue();
}

@Test
public void testProject() {
    Assertions.assertThat(config.isEnabled()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_COMMIT_SHA, "3");
    Assertions.assertThat(config.commitSHA()).isEqualTo("3");
    Assertions.assertThat(config.isEnabled()).isTrue();
    Assertions.assertThat(config.commentNoIssue()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_COMMENT_NO_ISSUE, "true");
    Assertions.assertThat(config.commentNoIssue()).isTrue();
    Assertions.assertThat(config.tryReportIssuesInline()).isTrue();
    settings.setProperty(GitLabPlugin.GITLAB_DISABLE_INLINE_COMMENTS, "true");
    Assertions.assertThat(config.tryReportIssuesInline()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_PROJECT_ID, "123");
    Assertions.assertThat(config.projectId()).isEqualTo("123");
    Assertions.assertThat(config.ignoreFileNotModified()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_IGNORE_FILE, "true");
    Assertions.assertThat(config.ignoreFileNotModified()).isTrue();
    settings.setProperty(GitLabPlugin.GITLAB_REF_NAME, "123");
    Assertions.assertThat(config.refName()).isEqualTo("123");
    Assertions.assertThat(config.onlyIssueFromCommitFile()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_ONLY_ISSUE_FROM_COMMIT_FILE, "true");
    Assertions.assertThat(config.onlyIssueFromCommitFile()).isTrue();
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.PENDING);
    settings.setProperty(GitLabPlugin.GITLAB_BUILD_INIT_STATE, BuildInitState.RUNNING.getMeaning());
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.RUNNING);
    settings.setProperty(GitLabPlugin.GITLAB_BUILD_INIT_STATE, "toto");
    Assertions.assertThat(config.buildInitState()).isEqualTo(BuildInitState.PENDING);
    Assertions.assertThat(config.disableGlobalComment()).isFalse();
    settings.setProperty(GitLabPlugin.GITLAB_DISABLE_GLOBAL_COMMENT, "true");
    Assertions.assertThat(config.disableGlobalComment()).isTrue();
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.COMMIT_STATUS);
    settings.setProperty(GitLabPlugin.GITLAB_STATUS_NOTIFICATION_MODE, StatusNotificationsMode.EXIT_CODE.getMeaning());
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.EXIT_CODE);
    settings.setProperty(GitLabPlugin.GITLAB_STATUS_NOTIFICATION_MODE, "toto");
    Assertions.assertThat(config.statusNotificationsMode()).isEqualTo(StatusNotificationsMode.COMMIT_STATUS);
}

public boolean pingUser() {
    return settings.getBoolean(GitLabPlugin.GITLAB_PING_USER);
}


@Test
public void testCommitAnalysisWithNewIssues() {
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, true, "msg1");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    PostJobIssue lineNotVisible = newMockedIssue("foo:src/Foo.php", inputFile1, 2, Severity.BLOCKER, true, "msg2");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 2)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L2");
    DefaultInputFile inputFile2 = new DefaultInputFile("foo", "src/Foo2.php");
    PostJobIssue fileNotInPR = newMockedIssue("foo:src/Foo2.php", inputFile2, 1, Severity.BLOCKER, true, "msg3");
    PostJobIssue notNewIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, false, "msg");
    PostJobIssue issueOnDir = newMockedIssue("foo:src", Severity.BLOCKER, true, "msg4");
    PostJobIssue issueOnProject = newMockedIssue("foo", Severity.BLOCKER, true, "msg");
    PostJobIssue globalIssue = newMockedIssue("foo:src/Foo.php", inputFile1, null, Severity.BLOCKER, true, "msg5");
    Mockito.when(context.issues()).thenReturn(Arrays.<PostJobIssue>asList(newIssue, globalIssue, issueOnProject, issueOnDir, fileNotInPR, lineNotVisible, notNewIssue));
    Mockito.when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    Mockito.when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("SonarQube analysis reported 5 issues"));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("* :no_entry: 5 blocker"));
    Mockito.verify(commitFacade).addGlobalComment(AdditionalMatchers.not(Mockito.contains("1. [Project")));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("1. :no_entry: [msg2](http://gitlab/blob/abc123/src/Foo.php#L2) [:blue_book:](http://myserver/coding_rules#rule_key=repo%3Arule)"));
    Mockito.verify(commitFacade).createOrUpdateSonarQubeStatus("failed", "SonarQube reported 5 issues, with 5 blocker");
}

@Test
public void testCommitAnalysisWithNewIssues() {
    settings.setProperty(GitLabPlugin.GITLAB_ONLY_ISSUE_FROM_COMMIT_FILE, false);
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, true, "msg1");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    PostJobIssue lineNotVisible = newMockedIssue("foo:src/Foo.php", inputFile1, 2, Severity.BLOCKER, true, "msg2");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 2)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L2");
    DefaultInputFile inputFile2 = new DefaultInputFile("foo", "src/Foo2.php");
    PostJobIssue fileNotInPR = newMockedIssue("foo:src/Foo2.php", inputFile2, 1, Severity.BLOCKER, true, "msg3");
    PostJobIssue notNewIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, false, "msg");
    PostJobIssue issueOnDir = newMockedIssue("foo:src", Severity.BLOCKER, true, "msg4");
    PostJobIssue issueOnProject = newMockedIssue("foo", Severity.BLOCKER, true, "msg");
    PostJobIssue globalIssue = newMockedIssue("foo:src/Foo.php", inputFile1, null, Severity.BLOCKER, true, "msg5");
    Mockito.when(context.issues()).thenReturn(Arrays.<PostJobIssue>asList(newIssue, globalIssue, issueOnProject, issueOnDir, fileNotInPR, lineNotVisible, notNewIssue));
    Mockito.when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    Mockito.when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("SonarQube analysis reported 6 issues"));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("* :no_entry: 6 blocker"));
    Mockito.verify(commitFacade).addGlobalComment(AdditionalMatchers.not(Mockito.contains("1. [Project")));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("1. :no_entry: [msg2](http://gitlab/blob/abc123/src/Foo.php#L2) [:blue_book:](http://myserver/coding_rules#rule_key=repo%3Arule)"));
    Mockito.verify(commitFacade).createOrUpdateSonarQubeStatus("failed", "SonarQube reported 6 issues, with 6 blocker");
}

@Override
public void execute(PostJobContext context) {
    GlobalReport report = new GlobalReport(gitLabPluginConfiguration, markDownUtils);
    try {
        Map<InputFile, Map<Integer, StringBuilder>> commentsToBeAddedByLine = processIssues(report, context.issues());
        updateReviewComments(commentsToBeAddedByLine);
        if (report.hasNewIssue() || gitLabPluginConfiguration.commentNoIssue()) {
            commitFacade.addGlobalComment(report.formatForMarkdown());
        }
        commitFacade.createOrUpdateSonarQubeStatus(report.getStatus(), report.getStatusDescription());
    } catch (Exception e) {
        String msg = "SonarQube failed to complete the review of this pull request";
        LOG.error(msg, e);
        commitFacade.createOrUpdateSonarQubeStatus("failed", msg + ": " + e.getMessage());
    }
}

@Override
public void execute(PostJobContext context) {
    GlobalReport report = new GlobalReport(gitLabPluginConfiguration, markDownUtils);
    try {
        LOG.info("Find a {} new issues", StreamSupport.stream(context.issues().spliterator(), false).filter(PostJobIssue::isNew).count());
        Map<InputFile, Map<Integer, StringBuilder>> commentsToBeAddedByLine = processIssues(report, context.issues());
        updateReviewComments(commentsToBeAddedByLine);
        if (report.hasNewIssue() || gitLabPluginConfiguration.commentNoIssue()) {
            commitFacade.addGlobalComment(report.formatForMarkdown());
        }
        commitFacade.createOrUpdateSonarQubeStatus(report.getStatus(), report.getStatusDescription());
    } catch (Exception e) {
        String msg = "SonarQube failed to complete the review of this commit";
        LOG.error(msg, e);
        commitFacade.createOrUpdateSonarQubeStatus("failed", msg + ": " + e.getMessage());
    }
}


@Test
public void testUnexpectedException() {
    String innerMsg = "Failed to get issues";
    when(context.issues()).thenThrow(new IllegalStateException(innerMsg));
    commitIssuePostJob.execute(context);
    String msg = "SonarQube failed to complete the review of this pull request: " + innerMsg;
    verify(commitFacade).createOrUpdateSonarQubeStatus("failed", msg);
}

@Test
public void testUnexpectedException() {
    String innerMsg = "Failed to get issues";
    when(context.issues()).thenThrow(new IllegalStateException(innerMsg));
    commitIssuePostJob.execute(context);
    String msg = "SonarQube failed to complete the review of this commit: " + innerMsg;
    verify(commitFacade).createOrUpdateSonarQubeStatus("failed", msg);
}

@Test
public void testCommitAnalysisWithNewIssues() {
    DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/Foo.php");
    PostJobIssue newIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, true, "msg1");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 1)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L1");
    PostJobIssue lineNotVisible = newMockedIssue("foo:src/Foo.php", inputFile1, 2, Severity.BLOCKER, true, "msg2");
    Mockito.when(commitFacade.getGitLabUrl(inputFile1, 2)).thenReturn("http://gitlab/blob/abc123/src/Foo.php#L2");
    DefaultInputFile inputFile2 = new DefaultInputFile("foo", "src/Foo2.php");
    PostJobIssue fileNotInPR = newMockedIssue("foo:src/Foo2.php", inputFile2, 1, Severity.BLOCKER, true, "msg3");
    PostJobIssue notNewIssue = newMockedIssue("foo:src/Foo.php", inputFile1, 1, Severity.BLOCKER, false, "msg");
    PostJobIssue issueOnDir = newMockedIssue("foo:src", Severity.BLOCKER, true, "msg4");
    PostJobIssue issueOnProject = newMockedIssue("foo", Severity.BLOCKER, true, "msg");
    PostJobIssue globalIssue = newMockedIssue("foo:src/Foo.php", inputFile1, null, Severity.BLOCKER, true, "msg5");
    Mockito.when(context.issues()).thenReturn(Arrays.<PostJobIssue>asList(newIssue, globalIssue, issueOnProject, issueOnDir, fileNotInPR, lineNotVisible, notNewIssue));
    Mockito.when(commitFacade.hasFile(inputFile1)).thenReturn(true);
    Mockito.when(commitFacade.hasFileLine(inputFile1, 1)).thenReturn(true);
    commitIssuePostJob.execute(context);
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("SonarQube analysis reported 6 issues"));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("* :no_entry: 6 blocker"));
    Mockito.verify(commitFacade).addGlobalComment(AdditionalMatchers.not(Mockito.contains("1. [Project")));
    Mockito.verify(commitFacade).addGlobalComment(Mockito.contains("1. :no_entry: [msg2](http://gitlab/blob/abc123/src/Foo.php#L2) [:blue_book:](http://myserver/coding_rules#rule_key=repo%3Arule)"));
    Mockito.verify(commitFacade).createOrUpdateSonarQubeStatus("failed", "SonarQube reported 6 issues, with 6 blocker");
}


@Test
public void testSettersWorkAsExpected() {
    final BotStatus botStatus = new BotStatus();
    assertNull(botStatus.getBotId());
    assertNull(botStatus.getDisplayName());
    assertNull(botStatus.getStatus());
    botStatus.setBotId(BOT_ID);
    assertEquals(BOT_ID, botStatus.getBotId());
    botStatus.setDisplayName(DISPLAY_NAME);
    assertEquals(DISPLAY_NAME, botStatus.getDisplayName());
    botStatus.setStatus(STATUS);
    assertEquals(STATUS, botStatus.getStatus());
}

@Test
public void testSettersWorkAsExpected() {
    final BotStatus botStatus = new BotStatus();
    assertNull(botStatus.getBotId());
    assertNull(botStatus.getDisplayName());
    assertNull(botStatus.getStatus());
    assertNull(botStatus.getDatetime());
    botStatus.setBotId(BOT_ID);
    assertEquals(BOT_ID, botStatus.getBotId());
    botStatus.setDisplayName(DISPLAY_NAME);
    assertEquals(DISPLAY_NAME, botStatus.getDisplayName());
    botStatus.setStatus(STATUS);
    assertEquals(STATUS, botStatus.getStatus());
    botStatus.setDatetime(null);
    assertNull(botStatus.getDatetime());
    botStatus.setDatetime(DATE);
    assertEquals(DATE.getTime(), botStatus.getDatetime().getTime());
}

public Date getDatetime() {
    return datetime != null ? new Date(datetime.getTime()) : null;
}

@Test
public void testToStringWorksAsExpected() {
    final BotStatus botStatus = new BotStatus(BOT_ID, DISPLAY_NAME, STATUS);
    assertEquals("BotStatus{botId=avro-707_1, displayName=Avro 707, status=running}", botStatus.toString());
}

@Test
public void testToStringWorksAsExpected() {
    final BotStatus botStatus = new BotStatus(BOT_ID, DISPLAY_NAME, STATUS, DATE);
    assertTrue(botStatus.toString().startsWith("BotStatus{botId=avro-707_1, displayName=Avro 707, status=running, datetime="));
}

@Override
public String toString() {
    return MoreObjects.toStringHelper(this).add("botId", botId).add("displayName", displayName).add("status", status).toString();
}

@Override
public String toString() {
    return MoreObjects.toStringHelper(this).add("botId", botId).add("displayName", displayName).add("status", status).add("datetime", getDatetime()).toString();
}

@Test
public void testInitialisationWorksAsExpected() {
    final BotStatus botStatus = new BotStatus(BOT_ID, DISPLAY_NAME, STATUS);
    assertEquals(BOT_ID, botStatus.getBotId());
    assertEquals(DISPLAY_NAME, botStatus.getDisplayName());
    assertEquals(STATUS, botStatus.getStatus());
}

@Test
public void testInitialisationWorksAsExpected() {
    final BotStatus botStatus = new BotStatus(BOT_ID, DISPLAY_NAME, STATUS, DATE);
    assertEquals(BOT_ID, botStatus.getBotId());
    assertEquals(DISPLAY_NAME, botStatus.getDisplayName());
    assertEquals(STATUS, botStatus.getStatus());
    assertEquals(DATE.getTime(), botStatus.getDatetime().getTime());
    final BotStatus botStatusNullDate = new BotStatus(BOT_ID, DISPLAY_NAME, STATUS, null);
    assertEquals(BOT_ID, botStatusNullDate.getBotId());
    assertEquals(DISPLAY_NAME, botStatusNullDate.getDisplayName());
    assertEquals(STATUS, botStatusNullDate.getStatus());
    assertNull(botStatusNullDate.getDatetime());
}


@Test
public void testGetSnippetDiscussionsByListWithMaxItems() throws Exception {
    List<Discussion> discussions = new DiscussionsApi(gitLabApi).getSnippetDiscussions(1, 1, 20);
    assertNotNull(discussions);
    assertTrue(compareJson(discussions, "snippet-discussions.json"));
}

@Test
public void testGetSnippetDiscussionsByListWithMaxItems() throws Exception {
    List<Discussion> discussions = new DiscussionsApi(gitLabApi).getSnippetDiscussions(1, 1L, 20);
    assertNotNull(discussions);
    assertTrue(compareJson(discussions, "snippet-discussions.json"));
}

public List<Discussion> getSnippetDiscussions(Object projectIdOrPath, Integer snippetId) throws GitLabApiException {
    Pager<Discussion> pager = getSnippetDiscussionsPager(projectIdOrPath, snippetId, getDefaultPerPage());
    return (pager.all());
}

public List<Discussion> getSnippetDiscussions(Object projectIdOrPath, Long snippetId, int maxItems) throws GitLabApiException {
    if (maxItems < 1) {
        return (getSnippetDiscussions(projectIdOrPath, snippetId));
    } else {
        Response response = get(Response.Status.OK, getPerPageQueryParam(maxItems), "projects", getProjectIdOrPath(projectIdOrPath), "snippets", snippetId, "discussions");
        return (response.readEntity(new GenericType<List<Discussion>>() {
        }));
    }
}

@Test
public void testGetSnippetDiscussionsByList() throws Exception {
    List<Discussion> discussions = new DiscussionsApi(gitLabApi).getSnippetDiscussions(1, 1);
    assertNotNull(discussions);
    assertTrue(compareJson(discussions, "snippet-discussions.json"));
}

@Test
public void testGetSnippetDiscussionsByList() throws Exception {
    List<Discussion> discussions = new DiscussionsApi(gitLabApi).getSnippetDiscussions(1, 1L);
    assertNotNull(discussions);
    assertTrue(compareJson(discussions, "snippet-discussions.json"));
}


@Test
public void trueBooleansAreSerializedCorrectly() throws Exception {
    new MergeRequestApi(mockGitLabApi).updateMergeRequest(1, 2, null, null, null, null, null, null, null, null, null, null, true);
    assertThat(attributeCaptor.getValue(), hasEntry("allow_collaboration", Collections.singletonList("true")));
}

@Test
public void trueBooleansAreSerializedCorrectly() throws Exception {
    new MergeRequestApi(mockGitLabApi).updateMergeRequest(1, 2L, null, null, null, null, null, null, null, null, null, null, true);
    assertThat(attributeCaptor.getValue(), hasEntry("allow_collaboration", Collections.singletonList("true")));
}

public MergeRequest updateMergeRequest(Object projectIdOrPath, Integer mergeRequestIid, MergeRequestParams params) throws GitLabApiException {
    GitLabApiForm form = params.getForm(false);
    Response response = put(Response.Status.OK, form.asMap(), "projects", getProjectIdOrPath(projectIdOrPath), "merge_requests", mergeRequestIid);
    return (response.readEntity(MergeRequest.class));
}

public MergeRequest updateMergeRequest(Object projectIdOrPath, Long mergeRequestIid, String targetBranch, String title, Long assigneeId, String description, StateEvent stateEvent, String labels, Long milestoneId, Boolean removeSourceBranch, Boolean squash, Boolean discussionLocked, Boolean allowCollaboration) throws GitLabApiException {
    String[] labelsArray = null;
    if (labels != null) {
        labelsArray = labels.split(",", -1);
    }
    MergeRequestParams params = new MergeRequestParams().withTargetBranch(targetBranch).withTitle(title).withAssigneeId(assigneeId).withDescription(description).withStateEvent(stateEvent).withLabels(labelsArray).withMilestoneId(milestoneId).withRemoveSourceBranch(removeSourceBranch).withDiscussionLocked(discussionLocked).withAllowCollaboration(allowCollaboration).withSquash(squash);
    return (updateMergeRequest(projectIdOrPath, mergeRequestIid, params));
}

@Test
public void whenAllArgumentsNull_thenNoAttributesSent() throws Exception {
    new MergeRequestApi(mockGitLabApi).updateMergeRequest(1, 2, null, null, null, null, null, null, null, null, null, null, null);
    assertEquals(0, attributeCaptor.getValue().size());
}

@Test
public void whenAllArgumentsNull_thenNoAttributesSent() throws Exception {
    new MergeRequestApi(mockGitLabApi).updateMergeRequest(1, 2L, null, null, null, null, null, null, null, null, null, null, null);
    assertEquals(0, attributeCaptor.getValue().size());
}

@Test
public void falseBooleansAreSerializedCorrectly() throws Exception {
    new MergeRequestApi(mockGitLabApi).updateMergeRequest(1, 2, null, null, null, null, null, null, null, null, null, null, false);
    assertThat(attributeCaptor.getValue(), hasEntry("allow_collaboration", Collections.singletonList("false")));
}

@Test
public void falseBooleansAreSerializedCorrectly() throws Exception {
    new MergeRequestApi(mockGitLabApi).updateMergeRequest(1, 2L, null, null, null, null, null, null, null, null, null, null, false);
    assertThat(attributeCaptor.getValue(), hasEntry("allow_collaboration", Collections.singletonList("false")));
}