package com.atlassian.stash.internal.hook;

import com.google.common.base.Ascii;
import com.google.common.base.Charsets;
import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.CharBuffer;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

public class SocketTransferInputTest {

    @Test
    public void testReadAsciiChar() throws Exception {
        char[] asciiChars = new char[Ascii.MAX - Ascii.MIN];
        for (int i = 0; i < asciiChars.length; i++) {
            asciiChars[i] = (char) (i + Ascii.MIN);
        }
        SocketTransferInput input = new SocketTransferInput(new ByteArrayInputStream(Charsets.US_ASCII.encode(CharBuffer.wrap(asciiChars)).array()));
        for (char c : asciiChars) {
            assertEquals(c, input.readAsciiChar());
        }
    }

    @Test
    public void testReadChunk() throws Exception {
        new SocketTransferInputTestDataBuilder()
                .addChunk(SocketTransferInput.ChunkType.REQUEST_ID, "cafebabe")
                .addChunk(SocketTransferInput.ChunkType.HOOK_TYPE, "git-update")
                .addChunk(SocketTransferInput.ChunkType.END, null)
                .replayAndVerify();
    }

    @Test
    public void testReadHookType() throws Exception {
        InputStream in = new SocketTransferInputTestDataBuilder()
                .addChunk(SocketTransferInput.ChunkType.HOOK_TYPE, "git-update")
                .buildInputStream();
        SocketTransferInput input = new SocketTransferInput(in);
        assertEquals("git-update", input.readHookType());
    }

    @Test(expected = IllegalStateException.class)
    public void testReadHookTypeOutOfOrder() throws Exception {
        InputStream in = new SocketTransferInputTestDataBuilder()
                .addChunk(SocketTransferInput.ChunkType.REQUEST_ID, "cafebabe")
                .buildInputStream();
        SocketTransferInput input = new SocketTransferInput(in);
        input.readHookType();
    }

    @Test(expected = IllegalStateException.class)
    public void testReadRequestIdOutOfOrder() throws Exception {
        InputStream in = new SocketTransferInputTestDataBuilder()
                .addChunk(SocketTransferInput.ChunkType.HOOK_TYPE, "git-update")
                .buildInputStream();
        SocketTransferInput input = new SocketTransferInput(in);
        input.readRequestId();
    }

    @Test
    public void testReadRequestId() throws Exception {
        InputStream in = new SocketTransferInputTestDataBuilder()
                .addChunk(SocketTransferInput.ChunkType.REQUEST_ID, "cafebabe")
                .buildInputStream();
        SocketTransferInput input = new SocketTransferInput(in);
        assertEquals("cafebabe", input.readRequestId());
    }

    @Test
    public void testReadSupplementary() throws IOException {
        String text = "\uD83D\uDCA9";
        InputStream in = new SocketTransferInputTestDataBuilder()
                .addChunk(SocketTransferInput.ChunkType.STDIN, text)
                .buildInputStream();
        SocketTransferInput input = new SocketTransferInput(in);
        assertEquals(text, input.readChunk().getValue());
    }

    @Test
    public void testClose() throws Exception {
        InputStream in = mock(InputStream.class);
        new SocketTransferInput(in).close();
        verify(in).close();
    }

    static void assertChunk(SocketTransferInput.Chunk chunk, SocketTransferInput.ChunkType type, String data) {
        assertNotNull(chunk);
        assertEquals(type, chunk.getType());
        assertEquals(data, chunk.getValue());
    }

}
