/*
 * @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.Comparator;
import java.util.NoSuchElementException;
import net.ranides.assira.collection.IntComparator;
import static net.ranides.assira.junit.NewAssert.*;
import org.junit.Test;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class ArraySearchTest {
    
    @Test
    public void testBinarySearch() {
        byte[] array1 = new byte[]{1,2,5,6};
        assertEquals(0, ArraySearch.binarySearch(array1, (byte)1));
        assertEquals(1, ArraySearch.binarySearch(array1, (byte)2));
        assertEquals(2, ArraySearch.binarySearch(array1, (byte)5));
        assertEquals(3, ArraySearch.binarySearch(array1, (byte)6));
        assertEquals(-5, ArraySearch.binarySearch(array1, (byte)9));
        assertEquals(-1, ArraySearch.binarySearch(array1, (byte)0));
        assertEquals(-3, ArraySearch.binarySearch(array1, (byte)3));
        assertEquals(-3, ArraySearch.binarySearch(array1, (byte)4));
        
        assertThrows(NullPointerException.class, ()->{
            ArraySearch.binarySearch(array1, null);
        });
    }
    
    @Test
    public void testBinarySearch_range() {
        byte[] array1 = new byte[]{4,1,2,5,6,9};
        assertEquals(1, ArraySearch.binarySearch(array1, 1, 5, (byte)1));
        assertEquals(2, ArraySearch.binarySearch(array1, 1, 5, (byte)2));
        assertEquals(3, ArraySearch.binarySearch(array1, 1, 5, (byte)5));
        assertEquals(4, ArraySearch.binarySearch(array1, 1, 5, (byte)6));
        assertEquals(-6, ArraySearch.binarySearch(array1, 1, 5, (byte)9));
        assertEquals(-2, ArraySearch.binarySearch(array1, 1, 5, (byte)0));
        assertEquals(-4, ArraySearch.binarySearch(array1, 1, 5, (byte)3));
        assertEquals(-4, ArraySearch.binarySearch(array1, 1, 5, (byte)4));
        
        assertThrows(NullPointerException.class, ()->{
            ArraySearch.binarySearch(array1, 1, 5, null);
        });
    }
    
    @Test
    public void testBinarySearch_cmp() {
        byte[] array1 = new byte[]{31,22,75,46};
        Comparator<Byte> cmp = (a,b) -> (a%10-b%10);
        assertEquals(0, ArraySearch.binarySearch(array1, (byte)1, cmp));
        assertEquals(1, ArraySearch.binarySearch(array1, (byte)92, cmp));
        assertEquals(2, ArraySearch.binarySearch(array1, (byte)95, cmp));
        assertEquals(3, ArraySearch.binarySearch(array1, (byte)96, cmp));
        assertEquals(-5, ArraySearch.binarySearch(array1, (byte)99, cmp));
        assertEquals(-1, ArraySearch.binarySearch(array1, (byte)90, cmp));
        assertEquals(-3, ArraySearch.binarySearch(array1, (byte)93, cmp));
        assertEquals(-3, ArraySearch.binarySearch(array1, (byte)94, cmp));
        
        assertThrows(NullPointerException.class, ()->{
            ArraySearch.binarySearch(array1, null, cmp);
        });
    }
    
    @Test
    public void testBinarySearch_cmp_range() {
        byte[] array1 = new byte[]{44,31,22,75,46,59};
        Comparator<Byte> cmp = (a,b) -> (a%10-b%10);
        assertEquals(1, ArraySearch.binarySearch(array1, 1, 5, (byte)1, cmp));
        assertEquals(2, ArraySearch.binarySearch(array1, 1, 5, (byte)92, cmp));
        assertEquals(3, ArraySearch.binarySearch(array1, 1, 5, (byte)95, cmp));
        assertEquals(4, ArraySearch.binarySearch(array1, 1, 5, (byte)96, cmp));
        assertEquals(-6, ArraySearch.binarySearch(array1, 1, 5, (byte)99, cmp));
        assertEquals(-2, ArraySearch.binarySearch(array1, 1, 5, (byte)90, cmp));
        assertEquals(-4, ArraySearch.binarySearch(array1, 1, 5, (byte)93, cmp));
        assertEquals(-4, ArraySearch.binarySearch(array1, 1, 5, (byte)94, cmp));
        
        assertThrows(NullPointerException.class, ()->{
            ArraySearch.binarySearch(array1, 1, 5, null, cmp);
        });
    }
    
    @Test
    public void testBinarySearch_int() {
        int[] array1 = new int[]{1,2,5,6};
        assertEquals(0, ArraySearch.binarySearch(array1, 1));
        assertEquals(1, ArraySearch.binarySearch(array1, 2));
        assertEquals(2, ArraySearch.binarySearch(array1, 5));
        assertEquals(3, ArraySearch.binarySearch(array1, 6));
        assertEquals(-5, ArraySearch.binarySearch(array1, 9));
        assertEquals(-1, ArraySearch.binarySearch(array1, 0));
        assertEquals(-3, ArraySearch.binarySearch(array1, 3));
        assertEquals(-3, ArraySearch.binarySearch(array1, 4));
    }
    
    @Test
    public void testBinarySearch_range_int() {
        int[] array1 = new int[]{4,1,2,5,6,9};
        assertEquals(1, ArraySearch.binarySearch(array1, 1, 5, (int)1));
        assertEquals(2, ArraySearch.binarySearch(array1, 1, 5, (int)2));
        assertEquals(3, ArraySearch.binarySearch(array1, 1, 5, (int)5));
        assertEquals(4, ArraySearch.binarySearch(array1, 1, 5, (int)6));
        assertEquals(-6, ArraySearch.binarySearch(array1, 1, 5, (int)9));
        assertEquals(-2, ArraySearch.binarySearch(array1, 1, 5, (int)0));
        assertEquals(-4, ArraySearch.binarySearch(array1, 1, 5, (int)3));
        assertEquals(-4, ArraySearch.binarySearch(array1, 1, 5, (int)4));
        
        assertThrows(NullPointerException.class, ()->{
            ArraySearch.binarySearch(array1, 1, 5, null);
        });
    }

    @Test
    public void testBinarySearch_cmp_int() {
        int[] array1 = new int[]{31,22,75,46};
        IntComparator cmp = (a,b) -> (a%10-b%10);
        assertEquals(0, ArraySearch.binarySearch(array1, 1, cmp));
        assertEquals(1, ArraySearch.binarySearch(array1, 92, cmp));
        assertEquals(2, ArraySearch.binarySearch(array1, 95, cmp));
        assertEquals(3, ArraySearch.binarySearch(array1, 96, cmp));
        assertEquals(-5, ArraySearch.binarySearch(array1, 99, cmp));
        assertEquals(-1, ArraySearch.binarySearch(array1, 90, cmp));
        assertEquals(-3, ArraySearch.binarySearch(array1, 93, cmp));
        assertEquals(-3, ArraySearch.binarySearch(array1, 94, cmp));
    }
    
    @Test
    public void testBinarySearch_cmp_range_int() {
        int[] array1 = new int[]{44,31,22,75,46,59};
        IntComparator cmp = (a,b) -> (a%10-b%10);
        assertEquals(1, ArraySearch.binarySearch(array1, 1, 5, (int)1, cmp));
        assertEquals(2, ArraySearch.binarySearch(array1, 1, 5, (int)92, cmp));
        assertEquals(3, ArraySearch.binarySearch(array1, 1, 5, (int)95, cmp));
        assertEquals(4, ArraySearch.binarySearch(array1, 1, 5, (int)96, cmp));
        assertEquals(-6, ArraySearch.binarySearch(array1, 1, 5, (int)99, cmp));
        assertEquals(-2, ArraySearch.binarySearch(array1, 1, 5, (int)90, cmp));
        assertEquals(-4, ArraySearch.binarySearch(array1, 1, 5, (int)93, cmp));
        assertEquals(-4, ArraySearch.binarySearch(array1, 1, 5, (int)94, cmp));
        
        assertThrows(NullPointerException.class, ()->{
            ArraySearch.binarySearch(array1, 1, 5, null, cmp);
        });
    }
    
    @Test
    public void testFirst() {
		String[] list8 = new String[]{"a", "b", "cc", "d", "ee", "f", "gg", "h"};

		assertThrows(NoSuchElementException.class, ()-> {
			ArraySearch.first(list8, v -> false).get();
		});
		assertThrows(NoSuchElementException.class, ()-> {
			ArraySearch.first(list8, 1, 3, v -> false).get();
		});
		
		assertEquals("b", ArraySearch.first(list8, 1, 3, v -> true).get());
		
		assertEquals("cc", ArraySearch.first(list8, (String v) -> v.length()>1).get());
		assertEquals("cc", ArraySearch.first(list8, 1, 3, (String v) -> v.length()>1).get());
		assertEquals("ee", ArraySearch.first(list8, 3, 5, (String v) -> v.length()>1).get());
    }
	
	@Test
    public void testLast() {
		String[] list8 = new String[]{"a", "b", "cc", "d", "ee", "f", "gg", "h"};

		assertThrows(NoSuchElementException.class, ()-> {
			ArraySearch.last(list8, v -> false).get();
		});
		assertThrows(NoSuchElementException.class, ()-> {
			ArraySearch.last(list8, 1, 3, v -> false).get();
		});
		
		assertEquals("d", ArraySearch.last(list8, 1, 4, v -> true).get());
		
		assertEquals("gg", ArraySearch.last(list8, (String v) -> v.length()>1).get());
		assertEquals("ee", ArraySearch.last(list8, 1, 6, (String v) -> v.length()>1).get());
		assertEquals("cc", ArraySearch.last(list8, 1, 3, (String v) -> v.length()>1).get());
    }
    
    @Test
    public void testIndexOf() {
        String[] list0 = new String[]{};
        String[] list1 = new String[]{"a"};
        String[] list8 = new String[]{"a", "b", "c", "d", "c", "e", "d", "f"};
        
        assertEquals(-1, ArraySearch.indexOf(list0, "q"));
        assertEquals(-1, ArraySearch.indexOf(list1, "q"));
        assertEquals(-1, ArraySearch.indexOf(list8, "q"));
        
        assertEquals(0, ArraySearch.indexOf(list1, "a"));
        assertEquals(2, ArraySearch.indexOf(list8, "c"));
        assertEquals(7, ArraySearch.indexOf(list8, "f"));
        
        assertThrows(IndexOutOfBoundsException.class, ()->{
            ArraySearch.indexOf(list1, 1, 3, "a");
        });
        
        assertEquals(0, ArraySearch.indexOf(list8, 0, 3, "a"));
        assertEquals(-1, ArraySearch.indexOf(list8, 1, 3, "a"));
        assertEquals(2, ArraySearch.indexOf(list8, 1, 6, "c"));
        assertEquals(4, ArraySearch.indexOf(list8, 3, 6, "c"));
    }
    
    @Test
    public void testLastIndexOf() {
        String[] list0 = new String[]{};
        String[] list1 = new String[]{"a"};
        String[] list8 = new String[]{"a", "b", "c", "d", "c", "e", "d", "f"};
        
        assertEquals(-1, ArraySearch.lastIndexOf(list0, "q"));
        assertEquals(-1, ArraySearch.lastIndexOf(list1, "q"));
        assertEquals(-1, ArraySearch.lastIndexOf(list8, "q"));
        
        assertEquals(0, ArraySearch.lastIndexOf(list1, "a"));
        assertEquals(4, ArraySearch.lastIndexOf(list8, "c"));
        assertEquals(7, ArraySearch.lastIndexOf(list8, "f"));
        
        assertThrows(IndexOutOfBoundsException.class, ()->{
            ArraySearch.lastIndexOf(list1, 1, 3, "a");
        });
        
        assertEquals(0, ArraySearch.lastIndexOf(list8, 0, 3, "a"));
        assertEquals(-1, ArraySearch.lastIndexOf(list8, 1, 3, "a"));
        assertEquals(4, ArraySearch.lastIndexOf(list8, 1, 6, "c"));
        assertEquals(2, ArraySearch.lastIndexOf(list8, 1, 3, "c"));
    }
    
    @Test
    public void testContains() {
        String[] list0 = new String[]{};
        String[] list1 = new String[]{"a"};
        String[] list8 = new String[]{"a", "b", "c", "d", "c", "e", "d", "f"};
        
        assertEquals(false, ArraySearch.contains(list0, "q"));
        assertEquals(false, ArraySearch.contains(list1, "q"));
        assertEquals(false, ArraySearch.contains(list8, "q"));
        
        assertEquals(true, ArraySearch.contains(list1, "a"));
        assertEquals(true, ArraySearch.contains(list8, "c"));
        assertEquals(true, ArraySearch.contains(list8, "f"));
        
        assertThrows(IndexOutOfBoundsException.class, ()->{
            ArraySearch.contains(list1, 1, 3, "a");
        });
        
        assertEquals(true, ArraySearch.contains(list8, 0, 3, "a"));
        assertEquals(false, ArraySearch.contains(list8, 1, 3, "a"));
        assertEquals(true, ArraySearch.contains(list8, 2, 6, "c"));
        assertEquals(false, ArraySearch.contains(list8, 2, 2, "c"));
        assertEquals(true, ArraySearch.contains(list8, 1, 6, "c"));
        assertEquals(true, ArraySearch.contains(list8, 3, 6, "c"));
    }
    
}
