package com.atlassian.stash.internal.concurrent;

import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class DefaultThreadLocalContextManagerTest {

    @Mock
    private StatefulService statefulService1;
    @Mock
    private TransferableState state1;

    @Mock
    private StatefulService statefulService2;
    @Mock
    private TransferableState state2;

    private DefaultThreadLocalContextManager manager;

    @Before
    public void setUp() throws Exception {
        when(statefulService1.getState()).thenReturn(state1);
        when(statefulService2.getState()).thenReturn(state2);

        manager = new DefaultThreadLocalContextManager();
        manager.setStatefulServices(statefulService1, statefulService2);
    }

    @Test
    public void testClearThreadLocalContext() throws Exception {
        // first set the current context
        manager.setThreadLocalContext(manager.getThreadLocalContext());
        // next clear it
        manager.clearThreadLocalContext();

        verify(state1).remove();
        verify(state2).remove();
    }

    @Test
    public void testGetThreadLocalContext() throws Exception {
        CompositeTransferableState threadState = manager.getThreadLocalContext();

        // verify that each of the stateful services has been called to get the state from
        verify(statefulService1).getState();
        verify(statefulService2).getState();

        assertEquals(Sets.newHashSet(state1, state2), Sets.newHashSet(threadState.getStates()));
    }

    @Test
    public void testSetThreadLocalContext() throws Exception {
        manager.setThreadLocalContext(new CompositeTransferableState(Sets.newHashSet(state1, state2)));

        verify(state1).apply();
        verify(state2).apply();
    }

    @Test
    public void testSetThreadLocalContextInvalidInput() throws Exception {
        manager.setThreadLocalContext(new Object()); // no exceptions on invalid input
        manager.setThreadLocalContext(null); // Handles null
    }
}
