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

import org.junit.Before;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
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 CrashLogger}.
 * <p/>
 * Created by marek.osvald on 2.5.2016.
 */
public class CrashLoggerTests {

    private static final String TAG = "tag";
    private static final String MESSAGE = "message";
    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
    private static final Throwable THROWABLE = mock(Throwable.class);
    private static final String FORMAT = "%s - %s";
    private static final String FORMATTED_STRING = "vararg1 - vararg2";
    private static final String VARARG1 = "vararg1";
    private static final String VARARG2 = "vararg2";

    private ILogger mLogger;

    @Before
    public void setUp() throws Exception {
        CrashLogger.init(null);
        mLogger = mock(ILogger.class);
    }

    @Test
    public void getLogger_loggerNull_returnsNull() throws Exception {
        // act
        ILogger logger = CrashLogger.getLogger();

        // assert
        assertThat(logger, nullValue());
    }

    @Test
    public void getLogger_loggerInit_returnsLogger() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        ILogger logger = CrashLogger.getLogger();

        // assert
        assertThat(logger, sameInstance(mLogger));
    }

    @Test
    public void v_crashLoggerInit_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.v(TAG, MESSAGE);

        // assert
        verify(mLogger, times(1)).v(TAG, MESSAGE);
    }

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

        // assert
        verify(mLogger, never()).v(anyString(), anyString());
    }

    @Test
    public void v_crashLoggerInitFormatter_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.v(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, times(1)).v(TAG, FORMATTED_STRING);
    }

    @Test
    public void v_crashLoggerNotInitFormatter_doesNotCrash() throws Exception {
        // act
        CrashLogger.v(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, never()).v(anyString(), anyString());
    }

    @Test
    public void v_crashLoggerInitThrowable_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.v(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mLogger, times(1)).v(TAG, MESSAGE, THROWABLE);
    }

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

        // assert
        verify(mLogger, never()).v(anyString(), anyString(), any(Throwable.class));
    }

    @Test
    public void d_crashLoggerInit_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.d(TAG, MESSAGE);

        // assert
        verify(mLogger, times(1)).d(TAG, MESSAGE);
    }

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

        // assert
        verify(mLogger, never()).d(anyString(), anyString());
    }

    @Test
    public void d_crashLoggerInitFormatter_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.d(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, times(1)).d(TAG, FORMATTED_STRING);
    }

    @Test
    public void d_crashLoggerNotInitFormatter_doesNotCrash() throws Exception {
        // act
        CrashLogger.d(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, never()).d(anyString(), anyString());
    }

    @Test
    public void d_crashLoggerInitThrowable_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.d(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mLogger, times(1)).d(TAG, MESSAGE, THROWABLE);
    }

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

        // assert
        verify(mLogger, never()).d(anyString(), anyString(), any(Throwable.class));
    }

    @Test
    public void i_crashLoggerInit_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.i(TAG, MESSAGE);

        // assert
        verify(mLogger, times(1)).i(TAG, MESSAGE);
    }

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

        // assert
        verify(mLogger, never()).i(anyString(), anyString());
    }

    @Test
    public void i_crashLoggerInitFormatter_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.i(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, times(1)).i(TAG, FORMATTED_STRING);
    }

    @Test
    public void i_crashLoggerNotInitFormatter_doesNotCrash() throws Exception {
        // act
        CrashLogger.i(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, never()).i(anyString(), anyString());
    }

    @Test
    public void i_crashLoggerInitThrowable_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.i(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mLogger, times(1)).i(TAG, MESSAGE, THROWABLE);
    }

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

        // assert
        verify(mLogger, never()).i(anyString(), anyString(), any(Throwable.class));
    }

    @Test
    public void w_crashLoggerInit_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.w(TAG, MESSAGE);

        // assert
        verify(mLogger, times(1)).w(TAG, MESSAGE);
    }

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

        // assert
        verify(mLogger, never()).w(anyString(), anyString());
    }

    @Test
    public void w_crashLoggerInitFormatter_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.w(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, times(1)).w(TAG, FORMATTED_STRING);
    }

    @Test
    public void w_crashLoggerNotInitFormatter_doesNotCrash() throws Exception {
        // act
        CrashLogger.w(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, never()).w(anyString(), anyString());
    }

    @Test
    public void w_crashLoggerInitThrowable_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.w(TAG, THROWABLE);

        // assert
        verify(mLogger, times(1)).w(TAG, THROWABLE);
    }

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

        // assert
        verify(mLogger, never()).w(anyString(), anyString(), any(Throwable.class));
    }

    @Test
    public void w_crashLoggerInitMessageThrowable_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.w(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mLogger, times(1)).w(TAG, MESSAGE, THROWABLE);
    }

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

        // assert
        verify(mLogger, never()).w(anyString(), anyString(), any(Throwable.class));
    }

    @Test
    public void e_crashLoggerInit_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.e(TAG, MESSAGE);

        // assert
        verify(mLogger, times(1)).e(TAG, MESSAGE);
    }

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

        // assert
        verify(mLogger, never()).e(anyString(), anyString());
    }

    @Test
    public void e_crashLoggerInitFormatter_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.e(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, times(1)).e(TAG, FORMATTED_STRING);
    }

    @Test
    public void e_crashLoggerNotInitFormatter_doesNotCrash() throws Exception {
        // act
        CrashLogger.e(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, never()).e(anyString(), anyString());
    }

    @Test
    public void e_crashLoggerInitThrowable_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.e(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mLogger, times(1)).e(TAG, MESSAGE, THROWABLE);
    }

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

        // assert
        verify(mLogger, never()).e(anyString(), anyString(), any(Throwable.class));
    }

    @Test
    public void wtf_crashLoggerInit_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.wtf(TAG, MESSAGE);

        // assert
        verify(mLogger, times(1)).wtf(TAG, MESSAGE);
    }

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

        // assert
        verify(mLogger, never()).wtf(anyString(), anyString());
    }

    @Test
    public void wtf_crashLoggerInitFormatter_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.wtf(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, times(1)).wtf(TAG, FORMATTED_STRING);
    }

    @Test
    public void wtf_crashLoggerNotInitFormatter_doesNotCrash() throws Exception {
        // act
        CrashLogger.wtf(TAG, FORMAT, VARARG1, VARARG2);

        // assert
        verify(mLogger, never()).wtf(anyString(), anyString());
    }

    @Test
    public void wtf_crashLoggerInitThrowable_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.wtf(TAG, THROWABLE);

        // assert
        verify(mLogger, times(1)).wtf(TAG, THROWABLE);
    }

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

        // assert
        verify(mLogger, never()).wtf(anyString(), anyString(), any(Throwable.class));
    }

    @Test
    public void wtf_crashLoggerInitMessageThrowable_logsMessage() throws Exception {
        // arrange
        CrashLogger.init(mLogger);

        // act
        CrashLogger.wtf(TAG, MESSAGE, THROWABLE);

        // assert
        verify(mLogger, times(1)).wtf(TAG, MESSAGE, THROWABLE);
    }

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

        // assert
        verify(mLogger, never()).wtf(anyString(), anyString(), any(Throwable.class));
    }

}
