package com.avg.zaap.crashlibrary.core.logger;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.runners.MockitoJUnitRunner;

import java.io.PrintStream;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

/**
 * A test class for {@link JavaSystemLogger}.
 * <p/>
 * Created by marek.osvald on 2.5.2016.
 */
@RunWith(MockitoJUnitRunner.class)
public class JavaSystemLoggerTests {

    private static final String FORMAT = "[%s] %s";
    private static final String TAG = "tag";
    private static final String MESSAGE = "message";
    @SuppressWarnings({"ThrowableResultOfMethodCallIgnored", "ThrowableInstanceNeverThrown"})
    private static final Throwable THROWABLE = new Throwable("message");

    private ILogger mJavaSystemLogger;
    private PrintStream mOutPrintStream;
    private PrintStream mErrPrintStream;

    @Captor
    private ArgumentCaptor<String> mCaptor;

    @Before
    public void setUp() throws Exception {
        mJavaSystemLogger = new JavaSystemLogger();
        mOutPrintStream = mock(PrintStream.class);
        mErrPrintStream = mock(PrintStream.class);

        System.setOut(mOutPrintStream);
        System.setErr(mErrPrintStream);
    }

    @Test
    public void v_nothing_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.v(TAG, MESSAGE);

        // assert
        verify(mOutPrintStream, times(1)).println(String.format(FORMAT, TAG, MESSAGE));
        verify(mErrPrintStream, never()).println(anyString());
    }

    @Test
    public void v_throwable_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.v(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mOutPrintStream, times(2)).println(mCaptor.capture());
        assertThat(mCaptor.getAllValues().size(), is(2));
        assertThat(mCaptor.getAllValues().get(0), is(String.format(FORMAT, TAG, MESSAGE)));
        assertThat(mCaptor.getAllValues().get(1), is(String.format(FORMAT, TAG, THROWABLE.getMessage())));
        verify(mErrPrintStream, never()).println(anyString());
    }

    @Test
    public void d_nothing_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.d(TAG, MESSAGE);

        // assert
        verify(mOutPrintStream, times(1)).println(String.format(FORMAT, TAG, MESSAGE));
        verify(mErrPrintStream, never()).println(anyString());
    }

    @Test
    public void d_throwable_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.d(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mOutPrintStream, times(2)).println(mCaptor.capture());
        assertThat(mCaptor.getAllValues().size(), is(2));
        assertThat(mCaptor.getAllValues().get(0), is(String.format(FORMAT, TAG, MESSAGE)));
        assertThat(mCaptor.getAllValues().get(1), is(String.format(FORMAT, TAG, THROWABLE.getMessage())));
        verify(mErrPrintStream, never()).println(anyString());
    }

    @Test
    public void i_nothing_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.i(TAG, MESSAGE);

        // assert
        verify(mOutPrintStream, times(1)).println(String.format(FORMAT, TAG, MESSAGE));
        verify(mErrPrintStream, never()).println(anyString());
    }

    @Test
    public void i_throwable_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.i(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mOutPrintStream, times(2)).println(mCaptor.capture());
        assertThat(mCaptor.getAllValues().size(), is(2));
        assertThat(mCaptor.getAllValues().get(0), is(String.format(FORMAT, TAG, MESSAGE)));
        assertThat(mCaptor.getAllValues().get(1), is(String.format(FORMAT, TAG, THROWABLE.getMessage())));
        verify(mErrPrintStream, never()).println(anyString());
    }

    @Test
    public void w_nothing_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.w(TAG, MESSAGE);

        // assert
        verify(mOutPrintStream, times(1)).println(String.format(FORMAT, TAG, MESSAGE));
        verify(mErrPrintStream, never()).println(anyString());
    }

    @Test
    public void w_throwable_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.w(TAG, THROWABLE);

        // assert
        verify(mOutPrintStream, times(1)).println(String.format(FORMAT, TAG, THROWABLE.getMessage()));
        verify(mErrPrintStream, never()).println(anyString());
    }

    @Test
    public void w_throwableMessage_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.w(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mOutPrintStream, times(2)).println(mCaptor.capture());
        assertThat(mCaptor.getAllValues().size(), is(2));
        assertThat(mCaptor.getAllValues().get(0), is(String.format(FORMAT, TAG, MESSAGE)));
        assertThat(mCaptor.getAllValues().get(1), is(String.format(FORMAT, TAG, THROWABLE.getMessage())));
        verify(mErrPrintStream, never()).println(anyString());
    }

    @Test
    public void e_nothing_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.e(TAG, MESSAGE);

        // assert
        verify(mErrPrintStream, times(1)).println(String.format(FORMAT, TAG, MESSAGE));
        verify(mOutPrintStream, never()).println(anyString());
    }

    @Test
    public void e_throwable_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.e(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mErrPrintStream, times(2)).println(mCaptor.capture());
        assertThat(mCaptor.getAllValues().size(), is(2));
        assertThat(mCaptor.getAllValues().get(0), is(String.format(FORMAT, TAG, MESSAGE)));
        assertThat(mCaptor.getAllValues().get(1), is(String.format(FORMAT, TAG, THROWABLE.getMessage())));
        verify(mOutPrintStream, never()).println(anyString());
    }

    @Test
    public void wtf_nothing_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.wtf(TAG, MESSAGE);

        // assert
        verify(mErrPrintStream, times(1)).println(String.format(FORMAT, TAG, MESSAGE));
        verify(mOutPrintStream, never()).println(anyString());
    }

    @Test
    public void wtf_throwable_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.wtf(TAG, THROWABLE);

        // assert
        verify(mErrPrintStream, times(1)).println(String.format(FORMAT, TAG, THROWABLE.getMessage()));
        verify(mOutPrintStream, never()).println(anyString());
    }

    @Test
    public void wtf_throwableMessage_printsMessageOut() throws Exception {
        // act
        mJavaSystemLogger.wtf(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mErrPrintStream, times(2)).println(mCaptor.capture());
        assertThat(mCaptor.getAllValues().size(), is(2));
        assertThat(mCaptor.getAllValues().get(0), is(String.format(FORMAT, TAG, MESSAGE)));
        assertThat(mCaptor.getAllValues().get(1), is(String.format(FORMAT, TAG, THROWABLE.getMessage())));
        verify(mOutPrintStream, never()).println(anyString());
    }

}
