package com.atlassian.stash.internal.hook.repository;

import com.atlassian.bitbucket.hook.HookResponse;
import com.atlassian.bitbucket.hook.repository.PreReceiveRepositoryHook;
import com.atlassian.bitbucket.hook.repository.RepositoryHookContext;
import com.atlassian.bitbucket.repository.RefChange;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.setting.Settings;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;

import javax.annotation.Nonnull;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static com.atlassian.stash.internal.hook.repository.RepositoryHookTestUtils.mockVisitEnabledHooks;
import static org.junit.Assert.*;

@RunWith(MockitoJUnitRunner.class)
public class PreReceiveRepositoryHookAdapterTest {

    @Mock
    private InternalRepositoryHookService hookService;

    @Mock
    private Settings settings;

    @Mock
    private Repository repository;

    @Test
    public void testOnReceiveDoesntProceedsAfterAnException() throws Exception {

        final List<String> results = new ArrayList<String>();

        PreReceiveRepositoryHook hook1 = new PreReceiveRepositoryHook() {
            @Override
            public boolean onReceive(@Nonnull RepositoryHookContext context, @Nonnull Collection<RefChange> refChanges, @Nonnull HookResponse hookResponse) {
                throw new RuntimeException("!");
            }
        };

        PreReceiveRepositoryHook hook2 = createHook(results, "hook2", true);

        mockVisitEnabledHooks(hookService, settings, hook1, hook2);
        HookResponse mock = Mockito.mock(HookResponse.class);
        StringWriter writer = new StringWriter();
        Mockito.when(mock.err()).thenReturn(new PrintWriter(writer));
        assertFalse(new PreReceiveRepositoryHookAdapter(hookService).onReceive(repository, null, mock));
        assertThat(writer.toString(), Matchers.containsString("failed"));
        assertTrue(results.isEmpty());
    }

    @Test
    public void testOnReceiveDoesntProceedsAfterAFalseReturnCode() throws Exception {

        final List<String> results = new ArrayList<String>();

        PreReceiveRepositoryHook hook1 = createHook(results, "hook1", false);

        PreReceiveRepositoryHook hook2 = createHook(results, "hook2", true);

        mockVisitEnabledHooks(hookService, settings, hook1, hook2);

        assertFalse(new PreReceiveRepositoryHookAdapter(hookService).onReceive(repository, null, null));
        assertEquals(1, results.size());
    }

    @Test
    public void testOnReceivesReturnTrue() throws Exception {

        final List<String> results = new ArrayList<String>();

        PreReceiveRepositoryHook hook1 = createHook(results, "hook1", true);

        PreReceiveRepositoryHook hook2 = createHook(results, "hook2", true);

        mockVisitEnabledHooks(hookService, settings, hook1, hook2);

        assertTrue(new PreReceiveRepositoryHookAdapter(hookService).onReceive(repository, null, null));
        assertEquals(2, results.size());
    }

    private PreReceiveRepositoryHook createHook(final List<String> results, final String result, final boolean value) {
        return new PreReceiveRepositoryHook() {
            @Override
            public boolean onReceive(@Nonnull RepositoryHookContext context, @Nonnull Collection<RefChange> refChanges, @Nonnull HookResponse hookResponse) {
                results.add(result);
                return value;
            }
        };
    }
}
