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

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.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.mockito.Mockito.when;

/**
 * A test class for {@link HashGenerator}.
 * <p>
 * Created by marek.osvald on 12.5.2016.
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest(HashGenerator.class)
public class HashGeneratorTests {

    private static final String SHA_1 = "SHA-1";

    private static final String CLASS_1 = "class1";
    private static final String CLASS_2 = "class2";
    private static final String CLASS_3 = "class3";

    private static final String METHOD_1 = "method1";
    private static final String METHOD_2 = "method2";
    private static final String METHOD_3 = "method3";

    private static final String FILE_1 = "file1";
    private static final String FILE_2 = "file2";
    private static final String FILE_3 = "file3";

    private static final int LINE_1 = 1;
    private static final int LINE_2 = 2;
    private static final int LINE_3 = 3;

    private static final StackTraceElement STACK_TRACE_ELEMENT_1 = new StackTraceElement(CLASS_1, METHOD_1, FILE_1, LINE_1);
    private static final StackTraceElement STACK_TRACE_ELEMENT_2 = new StackTraceElement(CLASS_2, METHOD_2, FILE_2, LINE_2);
    private static final StackTraceElement STACK_TRACE_ELEMENT_3 = new StackTraceElement(CLASS_3, METHOD_3, FILE_3, LINE_3);

    private HashGenerator mHashGenerator;

    @Before
    public void setUp() throws Exception {
        mHashGenerator = new HashGenerator();
    }

    @Test
    public void generateHash_order123_hash() throws Exception {
        // arrange
        StackTraceElement[] stacktrace = new StackTraceElement[]{
                STACK_TRACE_ELEMENT_1,
                STACK_TRACE_ELEMENT_2,
                STACK_TRACE_ELEMENT_3
        };

        // act
        final String result = mHashGenerator.generateHash(stacktrace);

        // assert
        assertThat(result, is("f335258cf21581b1eb309115583bba7b69ed47ad"));
    }

    @Test
    public void generateHash_order132_hash() throws Exception {
        // arrange
        StackTraceElement[] stacktrace = new StackTraceElement[]{
                STACK_TRACE_ELEMENT_1,
                STACK_TRACE_ELEMENT_3,
                STACK_TRACE_ELEMENT_2
        };

        // act
        final String result = mHashGenerator.generateHash(stacktrace);

        // assert
        //noinspection SpellCheckingInspection
        assertThat(result, is("fc4aa41eced9bf656d09ebb8018af1ce41436c8f"));
    }

    @Test
    public void generateHash_order213_hash() throws Exception {
        // arrange
        StackTraceElement[] stacktrace = new StackTraceElement[]{
                STACK_TRACE_ELEMENT_2,
                STACK_TRACE_ELEMENT_1,
                STACK_TRACE_ELEMENT_3
        };

        // act
        final String result = mHashGenerator.generateHash(stacktrace);

        // assert
        assertThat(result, is("608c364120dec27622c79a04682d7682f177ab6d"));
    }

    @Test
    public void generateHash_order231_hash() throws Exception {
        // arrange
        StackTraceElement[] stacktrace = new StackTraceElement[]{
                STACK_TRACE_ELEMENT_2,
                STACK_TRACE_ELEMENT_3,
                STACK_TRACE_ELEMENT_1
        };

        // act
        final String result = mHashGenerator.generateHash(stacktrace);

        // assert
        assertThat(result, is("46685d67bfc9fb051bb1394390e3536b63bd84eb"));
    }

    @Test
    public void generateHash_order312_hash() throws Exception {
        // arrange
        StackTraceElement[] stacktrace = new StackTraceElement[]{
                STACK_TRACE_ELEMENT_3,
                STACK_TRACE_ELEMENT_1,
                STACK_TRACE_ELEMENT_2
        };

        // act
        final String result = mHashGenerator.generateHash(stacktrace);

        // assert
        //noinspection SpellCheckingInspection
        assertThat(result, is("73d57b70f7a4427b1a6f166ba89f89a638fbda46"));
    }

    @Test
    public void generateHash_order321_hash() throws Exception {
        // arrange
        StackTraceElement[] stacktrace = new StackTraceElement[]{
                STACK_TRACE_ELEMENT_3,
                STACK_TRACE_ELEMENT_2,
                STACK_TRACE_ELEMENT_1
        };

        // act
        final String result = mHashGenerator.generateHash(stacktrace);

        // assert
        //noinspection SpellCheckingInspection
        assertThat(result, is("549d41d3d9706edecad7099f9649d47a6be2bd55"));
    }

    @Test
    public void generateHash_noSuchAlgorithmException_returnsNull() throws Exception {
        // arrange
        PowerMockito.mockStatic(MessageDigest.class);
        when(MessageDigest.getInstance(SHA_1)).thenThrow(new NoSuchAlgorithmException());

        StackTraceElement[] stacktrace = new StackTraceElement[]{
                STACK_TRACE_ELEMENT_1,
                STACK_TRACE_ELEMENT_2,
                STACK_TRACE_ELEMENT_3
        };

        // act
        final String result = mHashGenerator.generateHash(stacktrace);

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

}