package com.atlassian.bitbucket.scm.git.command;

import com.atlassian.bitbucket.NoSuchObjectException;
import com.atlassian.bitbucket.ServerException;
import com.atlassian.bitbucket.ServiceException;
import com.atlassian.bitbucket.commit.NoSuchCommitException;
import com.atlassian.bitbucket.content.NoSuchPathException;
import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.i18n.SimpleI18nService;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.scm.CommandFailedException;
import com.atlassian.utils.process.ProcessException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import java.io.IOException;

import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.mock;

@RunWith(MockitoJUnitRunner.class)
public class GitCommandExitHandlerTest {

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @InjectMocks
    private GitCommandExitHandler handler;
    @Spy
    @SuppressWarnings("unused")
    private I18nService i18nService = new SimpleI18nService();
    @Mock
    private Repository repository;

    @Test
    public void testBadRevision() {
        thrown.expect(NoSuchCommitException.class);
        thrown.expect(hasProperty("commitId", equalTo("foo")));

        handler.onCancel("/some/git/command", -1, "fatal: bad revision '^foo'", null);
    }

    @Test
    public void testBadRevisionWithExclude() {
        thrown.expect(NoSuchCommitException.class);
        thrown.expect(hasProperty("commitId", equalTo("foo-bar")));

        handler.onCancel("/some/git/command", -1, "fatal: bad revision 'foo-bar'", null);
    }

    @Test
    public void testBrokenPipe() {
        thrown.expect(CommandFailedException.class);

        handler.onExit("git diff", 128, "", new IOException("Broken pipe"));
    }

    @Test
    public void testNoSuchObject() {
        thrown.expect(NoSuchObjectException.class);
        thrown.expect(hasProperty("object", equalTo("nosuchstartpoint")));

        handler.onCancel("/some/git/command", -1, "fatal: Not a valid object name nosuchstartpoint", null);
    }

    @Test
    public void testNoSuchPath() {
        thrown.expect(NoSuchPathException.class);
        thrown.expect(hasProperty("object", equalTo("nosuchstartpoint")));
        thrown.expect(hasProperty("atObject", equalTo("atpoint")));

        handler.onCancel("/some/git/command", -1, "fatal: Not a valid object name atpoint:nosuchstartpoint", null);
    }

    @Test
    public void testProcessException() {
        ProcessException exception = new ProcessException("Testing");

        thrown.expect(ServerException.class);
        thrown.expectCause(sameInstance(exception));

        handler.onCancel("git cat-file -p master:pom.xml", 128, "", exception);
    }

    @Test
    public void testProcessExceptionForNonZeroExitCode() {
        ProcessException exception = new ProcessException("Non-zero exit code: 128", 128);

        thrown.expect(CommandFailedException.class);
        thrown.expectCause(sameInstance(exception));

        handler.onExit("git blame", 128, null, exception);
    }

    @Test
    public void testServiceException() {
        ServiceException exception = mock(ServiceException.class);

        thrown.expect(sameInstance(exception));

        handler.onExit("git diff-tree", 128, null, exception);
    }
}
