package com.atlassian.stash.internal.scm.git.command.branch;

import com.atlassian.bitbucket.repository.ConflictingRefNameException;
import com.atlassian.bitbucket.repository.DuplicateRefException;
import com.atlassian.bitbucket.InvalidNameException;
import com.atlassian.bitbucket.repository.InvalidRefNameException;
import com.atlassian.bitbucket.NoSuchObjectException;
import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.i18n.SimpleI18nService;
import com.atlassian.bitbucket.repository.Repository;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasProperty;
import static org.mockito.Mockito.mock;

public class CreateBranchCommandExitHandlerTest {

    private I18nService i18nService = new SimpleI18nService();
    private CreateBranchCommandExitHandler handler;

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

    @Before
    public void setUp() {
        handler = new CreateBranchCommandExitHandler(i18nService, mock(Repository.class));
    }

    @Test
    public void testInvalidBranchName() {
        thrown.expect(InvalidRefNameException.class);
        thrown.expect(hasProperty("refName", equalTo("branchname")));
        handler.onCancel("/some/git/command", -1, "fatal: 'branchname' is not a valid branch name.", null);
    }

    @Test
    public void testDuplicateBranchName() {
        thrown.expect(DuplicateRefException.class);
        thrown.expect(hasProperty("refName", equalTo("branchname")));
        handler.onCancel("/some/git/command", -1, "fatal: A branch named 'branchname' already exists.", null);
    }

    @Test
    public void testInvalidBranchPoint() {
        thrown.expect(InvalidNameException.class);
        handler.onCancel("/some/git/command", -1, "fatal: Not a valid branch point: '24eb2cf:pom.xml'.", null);
    }

    @Test
    public void testNoSuchBranchObject() {
        thrown.expect(NoSuchObjectException.class);
        thrown.expect(hasProperty("object", equalTo("nosuchstartpoint")));
        handler.onCancel("/some/git/command", -1, "fatal: Not a valid object name: 'nosuchstartpoint'.", null);
    }

    // Ref conflict error message for v2.5.0-rc0
    @Test
    public void testBranchNameConflictCannotLockRef() {
        thrown.expect(ConflictingRefNameException.class);
        thrown.expect(hasProperty("refName", equalTo("master/v1.0")));
        handler.onCancel("/some/git/command", -1,
                "fatal: cannot lock ref 'refs/heads/master/v1.0': 'refs/heads/master' exists; cannot create 'refs/heads/master/v1.0'", null);
    }

    // Ref conflict error message for v2.4.3 - 2.4.5
    @Test
    public void testBranchNameConflictCannotLockRefOldMessage() {
        thrown.expect(ConflictingRefNameException.class);
        thrown.expect(hasProperty("refName", equalTo("master/v1.0")));
        handler.onCancel("/some/git/command", -1,
                "fatal: Cannot lock ref 'refs/heads/master/v1.0': 'refs/heads/master' exists; cannot create 'refs/heads/master/v1.0'", null);
    }

    // Ref conflict error message for pre Git 2.4.3
    @Test
    public void testBranchNameConflictDirFileLooseRefs() {
        thrown.expect(ConflictingRefNameException.class);
        thrown.expect(hasProperty("refName", equalTo("release/v1.0")));
        handler.onCancel("/some/git/command", -1, "error: unable to resolve reference refs/heads/release/v1.0: Not a directory", null);
    }

    // Ref conflict error message for pre Git 2.4.3
    @Test
    public void testBranchNameConflictFileDirLooseRefs() {
        thrown.expect(ConflictingRefNameException.class);
        thrown.expect(hasProperty("refName", equalTo("bugfix")));
        handler.onCancel("/some/git/command", -1, "error: there are still refs under 'refs/heads/bugfix'", null);
    }

    // Ref conflict error message for pre Git 2.4.3
    @Test
    public void testBranchNameConflictPackedRefs() {
        thrown.expect(ConflictingRefNameException.class);
        thrown.expect(hasProperty("refName", equalTo("master/v1.0")));
        handler.onCancel("/some/git/command", -1, "error: 'refs/heads/master' exists; cannot create 'refs/heads/master/v1.0'", null);
    }
}
