package com.atlassian.bitbucket.installer.validation;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.io.File;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;

public class CompositeDirectoryValidationStrategyTest {
    @Rule
    public MockitoRule mockitoInit = MockitoJUnit.rule();

    @Mock
    private DirectoryValidationStrategy strategyOne;

    @Mock
    private DirectoryValidationStrategy strategyTwo;

    private CompositeDirectoryValidationStrategy composite;
    private File root = new File("someRandomFile");

    @Before
    public void setUp() throws Exception {
        composite = new CompositeDirectoryValidationStrategy(strategyOne, strategyTwo);
    }

    @Test
    public void testRunsAllValidations() {
        composite.validate(root);

        assertDelegatesCalledInOrder();
    }

    private void assertDelegatesCalledInOrder() {
        InOrder inOrder = Mockito.inOrder(strategyOne, strategyTwo);
        inOrder.verify(strategyOne).validate(root);
        inOrder.verify(strategyTwo).validate(root);
    }

    @Test(expected = HardValidationException.class)
    public void testThrowsFirstHardValidationError() {
        softFail(strategyOne);
        hardFail(strategyTwo);

        try {
            composite.validate(root);
        } finally {
            assertDelegatesCalledInOrder();
        }
    }

    @Test
    public void testThrowsSoftValidationErrorOnlyAfterAllOtherValidationsOccur() {
        softFail(strategyOne);
        noFail(strategyTwo);

        try {
            composite.validate(root);
            fail("Expected an exception.");
        } catch (SoftValidationException e) {
            //good.
        }

        assertDelegatesCalledInOrder();
    }

    private void hardFail(DirectoryValidationStrategy strategy) {
        doThrow(new HardValidationException("Hard")).when(strategy).validate(root);
    }

    private void softFail(DirectoryValidationStrategy strategy) {
        doThrow(new SoftValidationException("Soft")).when(strategy).validate(root);
    }

    private void noFail(DirectoryValidationStrategy strategy) {
        doNothing().when(strategy).validate(root);
    }
}