package com.avg.zaap.crashlibrary.core.helper.process;

import android.app.ActivityManager;
import android.content.Context;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;

import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
 * A test class for {@link ProcessHelper}.
 * <p/>
 * Created by marek.osvald on 14.7.2016.
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest({android.os.Process.class})
public class ProcessHelperTests {

    private static final String SERVICE_NAME = "com.avg.zaap.crashlibrary.crashservice";

    private static final String ATTRIBUTE_NAME_PROCESS_NAME = "processName";
    private static final String ATTRIBUTE_NAME_PID = "pid";
    private static final String PROCESS_NAME_1 = SERVICE_NAME;
    private static final String PROCESS_NAME_2 = "mockProcessName2";

    private static final int PROCESS_PID_1 = 1234;
    private static final int PROCESS_PID_2 = 4321;
    private static final int PROCESS_PID_3 = 6666;

    private IProcessHelper mProcessHelper;
    private Context mContext;
    @SuppressWarnings("FieldCanBeLocal")
    private ActivityManager mActivityManager;

    @Before
    public void setUp() throws Exception {
        PowerMockito.mockStatic(android.os.Process.class);

        mContext = mock(Context.class);
        mActivityManager = mock(ActivityManager.class);

        List<ActivityManager.RunningAppProcessInfo> processes = new ArrayList<>();

        ActivityManager.RunningAppProcessInfo runningAppProcessInfo1 = new ActivityManager.RunningAppProcessInfo(PROCESS_NAME_1, PROCESS_PID_1, new String[]{});
        Whitebox.setInternalState(runningAppProcessInfo1, ATTRIBUTE_NAME_PROCESS_NAME, PROCESS_NAME_1);
        Whitebox.setInternalState(runningAppProcessInfo1, ATTRIBUTE_NAME_PID, PROCESS_PID_1);
        processes.add(runningAppProcessInfo1);

        ActivityManager.RunningAppProcessInfo runningAppProcessInfo2 = new ActivityManager.RunningAppProcessInfo(PROCESS_NAME_2, PROCESS_PID_2, new String[]{});
        Whitebox.setInternalState(runningAppProcessInfo2, ATTRIBUTE_NAME_PROCESS_NAME, PROCESS_NAME_2);
        Whitebox.setInternalState(runningAppProcessInfo2, ATTRIBUTE_NAME_PID, PROCESS_PID_2);
        processes.add(runningAppProcessInfo2);

        when(mActivityManager.getRunningAppProcesses()).thenReturn(processes);
        when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(mActivityManager);

        mProcessHelper = new ProcessHelper();

        initializeProcess(Result.FOUND);
    }

    @Test
    public void getCurrentProcessName_processFound_returnsProcessName() throws Exception {
        // act
        final String result = mProcessHelper.getCurrentProcessName(mContext);

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

    @Test
    public void getCurrentProcessName_processNotFound_returnsNull() throws Exception {
        // arrange
        initializeProcess(Result.NOT_FOUND);

        // act
        final String result = mProcessHelper.getCurrentProcessName(mContext);

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

    @Test
    public void isReportingServiceProcess_serviceProcess_returnsTrue() throws Exception {
        // arrange
        initializeProcess(Result.FOUND);

        // act
        final boolean result = mProcessHelper.isReportingServiceProcess(mContext);

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

    @Test
    public void isReportingServiceProcess_notServiceProcess_returnsFalse() throws Exception {
        // arrange
        initializeProcess(Result.NOT_FOUND);

        // act
        final boolean result = mProcessHelper.isReportingServiceProcess(mContext);

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

    private void initializeProcess(Result result) {
        switch (result) {
            case FOUND:
                PowerMockito.when(android.os.Process.myPid()).thenReturn(PROCESS_PID_1);
                break;

            case NOT_FOUND:
                PowerMockito.when(android.os.Process.myPid()).thenReturn(PROCESS_PID_3);
                break;

            default:
                fail();
        }
    }

    enum Result {
        FOUND, NOT_FOUND
    }

}
