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

import org.junit.Test;
import static net.ranides.assira.junit.NewAssert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class NativeArrayAllocatorTest {
    
    
    
    @Test
    public void testEnsureCapacity_native() {
        NativeArray array1 = NativeArray.wrap(new byte[]{ 1,2,3,4,5,6 });
        
        assertSame(array1, NativeArrayAllocator.ensureCapacity(array1, 0));
        assertSame(array1, NativeArrayAllocator.ensureCapacity(array1, 3));
        assertSame(array1, NativeArrayAllocator.ensureCapacity(array1, 6));
        
        NativeArray array2 = NativeArrayAllocator.ensureCapacity(array1, 8);
        assertNotSame(array1, array2);
        assertArrayEquals(new byte[]{1,2,3,4,5,6,0,0}, array2.$array());
    }

    @Test
    public void testEnsureCapacity_Preserve_native() {
        NativeArray array1 = NativeArray.wrap(new byte[]{ 1,2,3,4,5,6 });
        
        assertSame(array1, NativeArrayAllocator.ensureCapacity(array1, 0, 0));
        assertSame(array1, NativeArrayAllocator.ensureCapacity(array1, 3, 0));
        assertSame(array1, NativeArrayAllocator.ensureCapacity(array1, 6, 0));
        
        NativeArray array2 = NativeArrayAllocator.ensureCapacity(array1, 8, 6);
        assertNotSame(array1, array2);
        assertArrayEquals(new byte[]{1,2,3,4,5,6,0,0}, array2.$array());
        
        NativeArray array3 = NativeArrayAllocator.ensureCapacity(array1, 8, 4);
        assertNotSame(array1, array3);
        assertArrayEquals(new byte[]{1,2,3,4,0,0,0,0}, array3.$array());
        
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureCapacity(array1, 8, 7);
        });
    }

    @Test
    public void testEnsureOffsetLength_native() {
        NativeArray array1 = NativeArray.wrap(new byte[4]);
        NativeArrayAllocator.ensureOffsetLength(array1, 1, 2);
        NativeArrayAllocator.ensureOffsetLength(array1, 0, 4);
        NativeArrayAllocator.ensureOffsetLength(array1, 1, 3);
        
        assertThrows(IllegalArgumentException.class, ()-> {
            NativeArrayAllocator.ensureOffsetLength(array1, 1, -1);
        });
        assertThrows(IllegalArgumentException.class, ()-> {
            NativeArrayAllocator.ensureOffsetLength(array1, 8, -1);
        });
        
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureOffsetLength(array1, -1, 1);
        });
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureOffsetLength(array1, 8, 1);
        });
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureOffsetLength(array1, 3, 10);
        });
    }

    @Test
    public void testEnsureOffsetLength_N() {
        NativeArrayAllocator.ensureOffsetLength(4, 1, 2);
        NativeArrayAllocator.ensureOffsetLength(4, 0, 4);
        NativeArrayAllocator.ensureOffsetLength(4, 1, 3);
        
        assertThrows(IllegalArgumentException.class, ()-> {
            NativeArrayAllocator.ensureOffsetLength(4, 1, -1);
        });
        assertThrows(IllegalArgumentException.class, ()-> {
            NativeArrayAllocator.ensureOffsetLength(4, 8, -1);
        });
        
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureOffsetLength(4, -1, 1);
        });
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureOffsetLength(4, 8, 1);
        });
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureOffsetLength(4, 3, 10);
        });
    }
    
    @Test
    public void testEnsureFromTo_native() {
        NativeArray array1 = NativeArray.wrap(new byte[4]);
        NativeArrayAllocator.ensureFromTo(array1, 1, 3);
        NativeArrayAllocator.ensureFromTo(array1, 0, 4);
        NativeArrayAllocator.ensureFromTo(array1, 1, 4);
        
        assertThrows(IllegalArgumentException.class, ()-> {
            NativeArrayAllocator.ensureFromTo(array1, 3, 1);
        });
        
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureFromTo(array1, -1, 8);
        });
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureFromTo(array1, 2, 8);
        });
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureFromTo(array1, 5, 6);
        });
    }

    @Test
    public void testEnsureFromTo_N() {
        NativeArrayAllocator.ensureFromTo(4, 1, 3);
        NativeArrayAllocator.ensureFromTo(4, 0, 4);
        NativeArrayAllocator.ensureFromTo(4, 1, 4);
        
        assertThrows(IllegalArgumentException.class, ()-> {
            NativeArrayAllocator.ensureFromTo(4, 3, 1);
        });
        
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureFromTo(4, -1, 8);
        });
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureFromTo(4, 2, 8);
        });
        assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
            NativeArrayAllocator.ensureFromTo(4, 5, 6);
        });
    }
    
    @Test
    public void testGrow_native() {
        NativeArray array1 = NativeArray.wrap(new byte[]{1,2,3});
        assertSame(array1, NativeArrayAllocator.grow(array1, 2));
        assertSame(array1, NativeArrayAllocator.grow(array1, 3));
        assertArrayEquals(new byte[]{1,2,3,0,0,0}, NativeArrayAllocator.grow(array1, 4).$array());
        assertArrayEquals(new byte[]{1,2,3,0,0,0}, NativeArrayAllocator.grow(array1, 5).$array());
        assertArrayEquals(new byte[]{1,2,3,0,0,0}, NativeArrayAllocator.grow(array1, 6).$array());
        assertArrayEquals(new byte[]{1,2,3,0,0,0,0}, NativeArrayAllocator.grow(array1, 7).$array());
        assertArrayEquals(new byte[]{1,2,3,0,0,0,0,0,0}, NativeArrayAllocator.grow(array1, 9).$array());
    }
    
    @Test
    public void testGrow_preserve_native() {
        NativeArray array1 = NativeArray.wrap(new byte[]{1,2,3});
        assertSame(array1, NativeArrayAllocator.grow(array1, 2, 2));
        assertSame(array1, NativeArrayAllocator.grow(array1, 3, 2));
        assertArrayEquals(new byte[]{1,2,0,0,0,0}, NativeArrayAllocator.grow(array1, 4, 2).$array());
        assertArrayEquals(new byte[]{1,2,0,0,0,0}, NativeArrayAllocator.grow(array1, 5, 2).$array());
        assertArrayEquals(new byte[]{1,2,0,0,0,0}, NativeArrayAllocator.grow(array1, 6, 2).$array());
        assertArrayEquals(new byte[]{1,2,0,0,0,0,0}, NativeArrayAllocator.grow(array1, 7, 2).$array());
        assertArrayEquals(new byte[]{1,2,0,0,0,0,0,0,0}, NativeArrayAllocator.grow(array1, 9, 2).$array());
    }

    @Test
    public void testTrim_A() {
        NativeArray array1 = NativeArray.wrap(new byte[]{1,2,3});
        
        assertSame(array1, NativeArrayAllocator.trim(array1, 5));
        assertSame(array1, NativeArrayAllocator.trim(array1, 3));
        assertArrayEquals(new byte[]{1,2}, NativeArrayAllocator.trim(array1, 2).$array());
        assertArrayEquals(new byte[]{1}, NativeArrayAllocator.trim(array1, 1).$array());
        assertArrayEquals(new byte[]{}, NativeArrayAllocator.trim(array1, 0).$array());
    }
	
	@Test
	public void testResize() {
		NativeArray a1 = NativeArray.wrap(new Integer[]{1,2,3});
		NativeArray o1 = NativeArrayAllocator.resize(a1, 0);
		NativeArray o2 = NativeArrayAllocator.resize(a1, 1);
		NativeArray o3 = NativeArrayAllocator.resize(a1, 3);
		NativeArray o4 = NativeArrayAllocator.resize(a1, 5);
		assertArrayEquals(new Integer[0], o1.$array());
		assertArrayEquals(new Integer[]{1}, o2.$array());
		assertSame(a1, o3);
		assertArrayEquals(new Integer[]{1,2,3,null,null}, o4.$array());
	}
	
	@Test
	public void testResize_native() {
		NativeArray a1 = NativeArray.wrap(new int[]{1,2,3});
		NativeArray o1 = NativeArrayAllocator.resize(a1, 0);
		NativeArray o2 = NativeArrayAllocator.resize(a1, 1);
		NativeArray o3 = NativeArrayAllocator.resize(a1, 3);
		NativeArray o4 = NativeArrayAllocator.resize(a1, 5);
		assertArrayEquals(new int[0], o1.$array());
		assertArrayEquals(new int[]{1}, o2.$array());
		assertSame(a1, o3);
		assertArrayEquals(new int[]{1,2,3,0,0}, o4.$array());
	}
	
	@Test
	public void testForComponent() {
		assertArrayEquals(new int[]{0,0,0,0}, NativeArrayAllocator.forComponent(int.class, 4).$array());
		assertArrayEquals(new Integer[]{null,null,null,null}, NativeArrayAllocator.forComponent(Integer.class, 4).$array());
	}
	
	@Test
	public void testForPrototype() {
		assertArrayEquals(new int[]{0,0,0,0}, NativeArrayAllocator.forPrototype(NativeArray.wrap(new int[1]), 4).$array());
		assertArrayEquals(new Integer[]{null,null,null,null}, NativeArrayAllocator.forPrototype(NativeArray.wrap(new Integer[1]), 4).$array());
	}
    
}
