package com.atlassian.stash.internal.aop;

import com.atlassian.crowd.model.user.InternalUser;
import com.atlassian.bitbucket.comment.CommentOutOfDateException;
import com.atlassian.bitbucket.AuthorisationException;
import com.atlassian.bitbucket.DataStoreException;
import com.atlassian.bitbucket.EntityOutOfDateException;
import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.i18n.SimpleI18nService;
import com.atlassian.stash.internal.backup.liquibase.LiquibaseDataAccessException;
import com.atlassian.stash.internal.comment.InternalComment;
import com.atlassian.stash.internal.pull.InternalPullRequest;
import com.atlassian.bitbucket.pull.PullRequestOutOfDateException;
import org.hibernate.HibernateException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.security.access.AccessDeniedException;

import java.lang.reflect.Method;

@RunWith(MockitoJUnitRunner.class)
public class ExceptionRewriteAdviceTest {

    private I18nService i18nService = new SimpleI18nService();

    private Method method;
    private ExceptionRewriteAdvice advice;

    @Before
    public void setUp() throws Exception {
        method = Object.class.getMethod("toString");
        advice = new ExceptionRewriteAdvice(i18nService);
    }

    @Test(expected = AuthorisationException.class)
    public void testRethrowAccessDenied() throws Exception {
        advice.afterThrowing(method, new Object[0], new Object(), new AccessDeniedException("a"));
    }

    @Test(expected = DataStoreException.class)
    public void testRethrowHibernate() throws Exception {
        advice.afterThrowing(method, new Object[0], new Object(), new HibernateException("a"));
    }

    @Test(expected = DataStoreException.class)
    public void testRethrowDataAccessException() throws Exception {
        advice.afterThrowing(method, new Object[0], new Object(), new LiquibaseDataAccessException("a", new Exception()));
    }

    @Test(expected = PullRequestOutOfDateException.class)
    public void testRethrowObjectOptimisticLockingFailureExceptionForPullRequests() throws Exception {
        advice.afterThrowing(method, new Object[0], new Object(), new ObjectOptimisticLockingFailureException(InternalPullRequest.class, 1));
    }

    @Test(expected = CommentOutOfDateException.class)
    public void testRethrowObjectOptimisticLockingFailureExceptionForComments() throws Exception {
        advice.afterThrowing(method, new Object[0], new Object(), new ObjectOptimisticLockingFailureException(InternalComment.class, 1));
    }

    @Test(expected = EntityOutOfDateException.class)
    public void testRethrowObjectOptimisticLockingFailureExceptionForOtherEntities() throws Exception {
        advice.afterThrowing(method, new Object[0], new Object(), new ObjectOptimisticLockingFailureException(InternalUser.class, 1));
    }

}
