/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.io.suite;

import java.io.IOException;
import java.io.InputStream;
import java.util.function.Function;
import net.ranides.assira.junit.TestContract;
import static org.junit.Assert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class InputStreamTester {
    
    @TestContract
    public void readBasic(Function<byte[], InputStream> f) throws IOException {
        InputStream istream = f.apply(new byte[]{21,22,23,24,25,26,27,28,29,30,31});
        
        int a = istream.read();
        assertEquals(21, (char)a);
        
        byte[] b = new byte[]{1,2,2,1,1,1};
        assertEquals(2, istream.read(b, 1, 2));
        assertArrayEquals(new byte[]{1,22,23,1,1,1}, b);

        assertEquals(0, istream.skip(-5));        
        assertEquals(5, istream.skip(5));
        
        assertEquals(istream.available(), istream.available());
        
        byte[] c = new byte[]{1,2,2,1,1,1};
        assertEquals(3, istream.read(c, 1, 4));
        assertArrayEquals(new byte[]{1,29,30,31,1,1}, c);
        
        assertEquals(0, istream.available());
        assertEquals(0, istream.available());
        
        assertEquals(0, istream.skip(3));
        assertEquals(-1, istream.read());
       
        istream.close();
        istream.close();
    }
    
    @TestContract
    public void readEOF(Function<byte[], InputStream> f) throws IOException {
        InputStream istream1 = f.apply(new byte[]{21,22,23,24,25,26,27,28,29,30,31});
        
        byte a1[] = new byte[6];
        assertEquals(6, istream1.read(a1));
        assertArrayEquals(new byte[]{21,22,23,24,25,26}, a1);
        
        byte b1[] = new byte[]{2,2,2,2,2,1,1,1,1};
        assertEquals(5, istream1.read(b1));
        assertArrayEquals(new byte[]{27,28,29,30,31,1,1,1,1}, b1);
        
        assertEquals(-1, istream1.read(b1));
        assertEquals(0, istream1.available());
        istream1.close();
        
        InputStream istream2 = f.apply(new byte[]{21,22,23,24,25,26,27,28,29,30,31});
        
        byte a2[] = new byte[6];
        assertEquals(6, istream2.read(a2));
        assertArrayEquals(new byte[]{21,22,23,24,25,26}, a2);
        
        assertEquals(istream2.available(), istream2.available());
        
        byte b2[] = new byte[]{2,2,2,2,2,1,1,1,1};
        assertEquals(5, istream2.read(b2));
        assertArrayEquals(new byte[]{27,28,29,30,31,1,1,1,1}, b2);
        
        assertEquals(0, istream2.available());
        assertEquals(-1, istream2.read(b2));
        istream2.close();
    }
    
    @TestContract
    public void mark(Function<byte[], InputStream> f) throws IOException {
        InputStream istream = f.apply(new byte[]{
			21,22,23,24,25
		});

        assertTrue("InputStream#markSupported", istream.markSupported());
        
        istream.mark(100);
        byte d[] = new byte[6];
        assertEquals(5, istream.read(d, 0, 5));
        assertArrayEquals(new byte[]{21,22,23,24,25,0}, d);
        
		byte e[] = new byte[5];
        assertEquals(-1, istream.read(e, 0, 30));
        assertEquals(-1, istream.read(e, 0, 30));
        istream.reset();
        assertEquals(5, istream.read(e, 0, 30));
        assertArrayEquals(new byte[]{21,22,23,24,25}, d);
        
        istream.close();
    }
    
    @TestContract
    public void skip(Function<byte[], InputStream> f) throws IOException {
        InputStream istream = f.apply(new byte[]{
            21,22,23,24,25,26,27,28,29,30,
            31,32,33,34,35,36,37,38,39,40,
            41,42,43,44,45,46,47,48,49,50
        });
        
        assertEquals(0,istream.skip(0));
        assertRead(new byte[]{21,22,23}, istream);
        
        assertTrue(istream.available() >= 0);
        assertEquals(0,istream.skip(0));
        assertRead(new byte[]{24,25,26}, istream);
        
        assertEquals(2,istream.skip(2));
        assertRead(new byte[]{29,30,31}, istream);
        
        assertTrue(istream.available() >= 0);
        assertEquals(2,istream.skip(2));
        assertRead(new byte[]{34,35,36}, istream);
        
        assertEquals(6, istream.skip(6));
        assertEquals(43, istream.read());
        
        assertEquals(7,istream.skip(10));
        assertEquals(-1, istream.read());
        assertEquals(0, istream.available());
        
        istream.close();
    }
//    
    private static void assertRead(byte[] expected, InputStream istream) throws IOException {
        byte[] buffer = new byte[expected.length];
        assertEquals(expected.length, istream.read(buffer));
        assertArrayEquals(expected, buffer);
    }
    
}
