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

import java.util.Random;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import net.ranides.assira.collection.IntComparator;
import net.ranides.assira.ContractTesters;
import net.ranides.assira.generic.CompareUtils;
import net.ranides.assira.generic.HashUtils;
import net.ranides.assira.test.TCollection;
import org.junit.Test;
import static net.ranides.assira.junit.NewAssert.*;
import net.ranides.assira.junit.TestContractRunner;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class NativeArrayTest {
    
    
    private static <T> boolean run(IntFunction<T> function) {
        return ContractTesters.runner().apply(box(function)).run();
    }
    
    private static <T> Consumer<TestContractRunner> box(IntFunction<T> function) {
        TValues<T> var = new TValues<>(function);
        return r -> {
            r.param("collection!", var);
            r.function(new int[0], array -> NativeArray.wrap(var.list(array).values()).unbox());
        };
    }

    @Test
    public void testSuite() {
        run(index -> (byte)index );
        run(index -> (int)index );
        run(index -> (short)index );
        run(index -> (long)index );
        run(index -> (float)0.75*index );
        run(index -> (double)0.75*index );
        run(index -> (char)('a'+index) );
        run(index -> String.format("%02d", index) );
        
        ContractTesters.runner()
            .ignore("NativeArrayTester.testCompare")
            .ignore("NativeArrayTester.testCompare_cmp")
            .apply(box(index -> new Random(1027*index).nextBoolean()))
            .run();
    }

    
	
	@Test
    public void testAllocateErrors() {
		assertThrows(UnsupportedOperationException.class, ()->{
			NativeArray.allocate(Void.TYPE, 4);
		});
	}
	
	@Test
    public void testWrapErrors() {
		assertThrows(IllegalArgumentException.class, ()->{
			NativeArray.wrap(Integer.valueOf(17));
		});
	}
    
    @Test
    public void testBoxing() {
        final NativeArray na1i = NativeArray.wrap(new int[]{1,2});
        final NativeArray na2i = na1i.box();
        final NativeArray na3i = na2i.unbox();
        assertArrayEquals(new Integer[]{1,2}, na1i.box().$array());
        assertSame(na2i, na2i.box());
        assertArrayEquals(new int[]{1,2}, na3i.$array());
        assertSame(na3i, na3i.unbox());
        
        final NativeArray na1c = NativeArray.wrap(new char[]{'a','b'});
        final NativeArray na2c = na1c.box();
        final NativeArray na3c = na2c.unbox();
        assertArrayEquals(new Character[]{'a','b'}, na1c.box().$array());
        assertSame(na2c, na2c.box());
        assertArrayEquals(new char[]{'a','b'}, na3c.$array());
        assertSame(na3c, na3c.unbox());
    }
	
	@Test
    public void basicComparator_cmp_int() {
        NativeArray target = NativeArray.wrap(new int[]{1,3,5,7,2});
		
		IntComparator fcmp = Integer::compare;
		
        IntComparator icmp = target.comparator(fcmp.reversed());
        
        assertEquals(Integer.compare(3,1), icmp.compare(0,1));
        assertEquals(Integer.compare(5,3), icmp.compare(1,2));
        assertEquals(Integer.compare(7,1), icmp.compare(0,3));
        assertEquals(Integer.compare(1,7), icmp.compare(3,0));
        assertEquals(Integer.compare(5,5), icmp.compare(2,2));
        assertEquals(Integer.compare(2,3), icmp.compare(1,4));
        
        NativeArray array = NativeArray.wrap(new int[]{4,5,9,3,1});
        IntComparator acmp = target.comparator(array, fcmp.reversed());
        
        assertEquals(Integer.compare(5,1), acmp.compare(0,1));
        assertEquals(Integer.compare(9,3), acmp.compare(1,2));
        assertEquals(Integer.compare(3,1), acmp.compare(0,3));
        assertEquals(Integer.compare(4,7), acmp.compare(3,0));
        assertEquals(Integer.compare(9,5), acmp.compare(2,2));
        assertEquals(Integer.compare(1,3), acmp.compare(1,4));
    }
    
    private static class TValues<T> extends TCollection<T> {

        private final IntFunction<T> function;
        
        public TValues(IntFunction<T> function) {
            this.function = function;
        }

        @Override
        protected T value(int index, int n) {
            if(n!=0) {
                throw new UnsupportedOperationException("NO TEST");
            }
            return function.apply(index);
        }

        @Override
        protected int cmp(Object a, Object b) {
            return CompareUtils.cmp(a, b);
        }

        @Override
        protected int hash(Object value) {
            return HashUtils.hash(value);
        }
        
    }
	
}
