package com.avg.zaap.crashlibrary.provider;

import android.os.Debug;

import com.avg.zaap.crashlibrary.provider.memory.MemoryHeapProvider;

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 java.io.File;
import java.io.IOException;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
import static org.powermock.api.support.membermodification.MemberMatcher.method;

/**
 * A test class for {@link MemoryHeapProvider} class.
 * <p>
 * Created by marek.osvald on 12.4.2016.
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest({Debug.class})
public class MemoryHeapProviderTests {

    private static final String DIRECTORY = "/foo/bar";
    private static final String FILE_NAME = "dump.dalvik.hprof";
    private static final String FILE_PATH = DIRECTORY + File.separatorChar + FILE_NAME;

    private MemoryHeapProvider mMemoryHeapProvider;

    @Before
    public void setUp() throws Exception {
        mMemoryHeapProvider = new MemoryHeapProvider();
        initializeDebug(Result.OK);
    }

    @Test
    public void provideData_everythingOK_returnsFilePath() throws Exception {
        // act
        final String result = mMemoryHeapProvider.provideData(DIRECTORY);

        // assert
        assertThat(result, is(FILE_PATH));
        PowerMockito.verifyStatic(times(1));
        Debug.dumpHprofData(FILE_PATH);
    }

    @Test
    public void provideData_ioException_exceptionThrown() throws Exception {
        // arrange
        initializeDebug(Result.EXCEPTION_IO);

        // act
        try {
            mMemoryHeapProvider.provideData(DIRECTORY);
            fail();
        } catch (CrashProviderException ok) { /* ignored */ }

        // assert
        PowerMockito.verifyStatic(times(1));
        Debug.dumpHprofData(FILE_PATH);
    }

    @Test
    public void provideData_unsupportedOperation_exceptionThrown() throws Exception {
        // arrange
        initializeDebug(Result.EXCEPTION_UNSUPPORTED);

        // act
        try {
            mMemoryHeapProvider.provideData(DIRECTORY);
            fail();
        } catch (CrashProviderException ok) { /* ignored */ }

        // assert
        PowerMockito.verifyStatic(times(1));
        Debug.dumpHprofData(FILE_PATH);
    }

    private void initializeDebug(Result result) throws Exception {
        PowerMockito.mockStatic(Debug.class);

        switch (result) {
            case OK:
                PowerMockito.doNothing().when(Debug.class, method(Debug.class, "dumpHprofData", String.class)).withArguments(anyString());
                break;

            case EXCEPTION_IO:
                PowerMockito.when(Debug.class, method(Debug.class, "dumpHprofData", String.class)).withArguments(anyString()).thenThrow(new IOException());
                break;

            case EXCEPTION_UNSUPPORTED:
                PowerMockito.when(Debug.class, method(Debug.class, "dumpHprofData", String.class)).withArguments(anyString()).thenThrow(new UnsupportedOperationException());
                break;
        }
    }

    enum Result {
        OK, EXCEPTION_UNSUPPORTED, EXCEPTION_IO
    }

}
