package com.avg.zaap.crashlibrary;

import android.os.Parcel;

import com.avg.zaap.crashlibrary.offline.Connection;

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

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

/**
 * A test class for {@link ConnectionStatus}.
 * <p/>
 * Created by marek.osvald on 10.8.2016.
 */
public class ConnectionStatusTests {

    private static final int MOCK_FLAGS = 1;
    private static final int NO_MASK = 0;

    private static final int TRUE = 1;
    private static final int FALSE = 0;

    private ConnectionStatus mConnectionStatus;
    private Parcel mParcel;

    @Before
    public void setUp() throws Exception {
        mParcel = mock(Parcel.class);
        mConnectionStatus = new ConnectionStatus();
        initializeParcel();
    }

    @Test
    public void constructor_parcel_recreatesConnectionStatus() throws Exception {
        // act
        mConnectionStatus = new ConnectionStatus(mParcel);

        // assert
        assertThat(mConnectionStatus.getConnection(), is(Connection.OTHER));
        assertThat(mConnectionStatus.isConnected(), is(true));
        assertThat(mConnectionStatus.isRoaming(), is(false));
        verify(mParcel, times(3)).readInt();
        verifyNoMoreInteractions(mParcel);
    }

    @Test
    public void getConnection_nothing_returnsConnection() throws Exception {
        // arrange
        mConnectionStatus.setConnection(Connection.MOBILE);

        // act
        final Connection result = mConnectionStatus.getConnection();

        // assert
        assertThat(result, is(Connection.MOBILE));
    }

    @Test
    public void setConnection_nothing_setsConnection() throws Exception {
        // arrange
        mConnectionStatus.setConnection(Connection.MOBILE);
        assertThat(mConnectionStatus.getConnection(), is(Connection.MOBILE));

        // act
        mConnectionStatus.setConnection(Connection.WIFI);
        final Connection result = mConnectionStatus.getConnection();

        // assert
        assertThat(result, is(Connection.WIFI));
    }

    @Test
    public void isConnected_nothing_setsConnected() throws Exception {
        // arrange
        mConnectionStatus.setConnected(true);

        // act
        final boolean result = mConnectionStatus.isConnected();

        // assert
        assertThat(result, is(true));
    }

    @Test
    public void setConnected_nothing_setsConnected() throws Exception {
        // arrange
        mConnectionStatus.setConnected(true);
        assertThat(mConnectionStatus.isConnected(), is(true));

        // act
        mConnectionStatus.setConnected(false);
        final boolean result = mConnectionStatus.isConnected();

        // assert
        assertThat(result, is(false));
    }

    @Test
    public void isRoaming_nothing_returnsRoaming() throws Exception {
        // arrange
        mConnectionStatus.setRoaming(true);

        // act
        final boolean result = mConnectionStatus.isRoaming();

        // assert
        assertThat(result, is(true));
    }

    @Test
    public void setRoaming_nothing_setsRoaming() throws Exception {
        // arrange
        mConnectionStatus.setRoaming(true);
        assertThat(mConnectionStatus.isRoaming(), is(true));

        // act
        mConnectionStatus.setRoaming(false);
        final boolean result = mConnectionStatus.isRoaming();

        // assert
        assertThat(result, is(false));
    }

    @Test
    public void describeContents_nothing_returnsNoMask() throws Exception {
        // act
        final int result = mConnectionStatus.describeContents();

        // assert
        assertThat(result, is(NO_MASK));
    }

    @Test
    public void writeToParcel_connectedMobileRoaming_writesAllValues() throws Exception {
        // arrange
        mConnectionStatus.setConnected(true);
        mConnectionStatus.setConnection(Connection.MOBILE);
        mConnectionStatus.setRoaming(true);

        // act
        mConnectionStatus.writeToParcel(mParcel, MOCK_FLAGS);

        // assert
        verify(mParcel, times(2)).writeInt(1); // roaming: true, connected: true
        verify(mParcel, times(1)).writeInt(Connection.MOBILE.ordinal());
        verify(mParcel, never()).writeInt(Connection.NONE.ordinal());
        verify(mParcel, never()).writeInt(Connection.WIFI.ordinal());
        verifyNoMoreInteractions(mParcel);
    }

    @Test
    public void writeToParcel_notConnectedWifi_writesAllValues() throws Exception {
        // arrange
        mConnectionStatus.setConnected(false);
        mConnectionStatus.setConnection(Connection.WIFI);
        mConnectionStatus.setRoaming(false);

        // act
        mConnectionStatus.writeToParcel(mParcel, MOCK_FLAGS);

        // assert
        verify(mParcel, times(2)).writeInt(0); // connected: false, roaming: false and connected: true
        verify(mParcel, times(1)).writeInt(Connection.WIFI.ordinal());
        verify(mParcel, never()).writeInt(Connection.OTHER.ordinal());
        verify(mParcel, never()).writeInt(Connection.MOBILE.ordinal());
        verifyNoMoreInteractions(mParcel);
    }

    @Test
    public void writeToParcel_notConnectedNone_writesAllValues() throws Exception {
        // arrange
        mConnectionStatus.setConnected(false);
        mConnectionStatus.setConnection(Connection.NONE);
        mConnectionStatus.setRoaming(false);

        // act
        mConnectionStatus.writeToParcel(mParcel, MOCK_FLAGS);

        // assert
        verify(mParcel, times(3)).writeInt(0); // NONE, connected: false, roaming: false
        verify(mParcel, never()).writeInt(Connection.MOBILE.ordinal());
        verify(mParcel, never()).writeInt(Connection.OTHER.ordinal());
        verify(mParcel, never()).writeInt(Connection.WIFI.ordinal());
        verifyNoMoreInteractions(mParcel);
    }

    @Test
    public void writeToParcel_notConnectedOther_writesAllValues() throws Exception {
        // arrange
        mConnectionStatus.setConnected(false);
        mConnectionStatus.setConnection(Connection.OTHER);
        mConnectionStatus.setRoaming(false);

        // act
        mConnectionStatus.writeToParcel(mParcel, MOCK_FLAGS);

        // assert
        verify(mParcel, times(2)).writeInt(0); // connected: false, roaming: false
        verify(mParcel, times(1)).writeInt(Connection.OTHER.ordinal());
        verify(mParcel, never()).writeInt(Connection.MOBILE.ordinal());
        verify(mParcel, never()).writeInt(Connection.WIFI.ordinal());
        verifyNoMoreInteractions(mParcel);
    }

    @Test
    public void toString_nothing_returnsString() throws Exception {
        // act
        String result = mConnectionStatus.toString();

        // assert
        //@formatter:off
        assertThat(result,
                is("ConnectionStatus {" +
                                "mConnection=" + mConnectionStatus.getConnection() + ", " +
                                "mConnected=" + mConnectionStatus.isConnected() + ", " +
                                "mRoaming=" + mConnectionStatus.isRoaming() + " " +
                   "}"
                )
        );
        //@formatter:on
    }

    private void initializeParcel() {
        when(mParcel.readInt()).thenReturn(Connection.OTHER.ordinal(), TRUE, FALSE);
    }

}
