package org.jboss.resteasy.test.client;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

import org.jboss.resteasy.client.jaxrs.engines.SelfExpandingBufferredInputStream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

/**
 * @tpSubChapter Resteasy-client
 * @tpChapter Client tests
 * @tpTestCaseDetails Unit test for SelfExpandingBufferredInputStream
 * @tpSince RESTEasy 3.0.16
 */
public class SelfExpandingBufferredInputStreamTest {
    String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    InputStream input;
    SelfExpandingBufferredInputStream stream;
    InputStream control;

    @BeforeEach
    public void setUp() {
        input = new ByteArrayInputStream(data.getBytes());
        control = new ByteArrayInputStream(data.getBytes());
        stream = new SelfExpandingBufferredInputStream(input, 1);
    }

    /**
     * @tpTestDetails Test not supported mark
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testMarkNotSupported() {
        UnsupportedOperationException thrown = Assertions.assertThrows(UnsupportedOperationException.class,
                () -> {
                    stream.mark(256);
                });
        Assertions.assertTrue(thrown instanceof UnsupportedOperationException);
    }

    /**
     * @tpTestDetails Test for buffer auto expands read
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBufferAutoExpandsRead() throws Exception {
        stream.read();
        assertEquals(1, stream.getBufSize());
        stream.read();
        assertEquals(2, stream.getBufSize());
        stream.read(new byte[2]);
        assertEquals(4, stream.getBufSize());
        stream.read(new byte[2]);
        assertEquals(8, stream.getBufSize());
        assertEquals(6, stream.getPos());
    }

    /**
     * @tpTestDetails Test for reset returns to position zero
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testResetReturnsToPositionZero() throws Exception {
        stream.read(new byte[7]);
        assertEquals(8, stream.getBufSize());
        assertEquals(7, stream.getPos());
        stream.reset();
        assertEquals(8, stream.getBufSize());
        assertEquals(0, stream.getPos());
    }

    /**
     * @tpTestDetails Test for reset and read over buffer
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testResetAndReadOverMarklengthContinuesToExpandBuffer() throws Exception {
        byte[] f7 = new byte[7];
        stream.read(f7);
        assertEquals(8, stream.getBufSize());

        stream.reset();
        assertEquals(8, stream.getBufSize());

        byte[] f13 = new byte[13];
        stream.read(f13);
        assertEquals(16, stream.getBufSize());
    }

    /**
     * @tpTestDetails Test for read and reset data
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testReadResetReReadReturnsSameData() throws Exception {
        byte[] first = new byte[7];
        stream.read(first);

        stream.reset();
        stream.read(new byte[19]);
        stream.reset();

        byte[] second = new byte[7];
        stream.read(second);
        assertByteArrayEquals(first, second);
    }

    /**
     * @tpTestDetails Test for read offset
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testReadOffsetExpandsBuffer() throws Exception {
        byte[] f7 = new byte[7];
        stream.read(f7, 1, 6);
        assertEquals(8, stream.getBufSize());
    }

    private void assertByteArrayEquals(byte[] first, byte[] second) {
        assertEquals(new String(first), new String(second));
    }
}
