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

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class SingleCollectionTest {
    
    public SingleCollectionTest() {
    }

    @Test
    public void testRO() {
        SingleCollection<Integer> c1 = new SingleCollection<>(12);
        Collection<Integer> c2 = SingleCollection.of(12);
        Collection<Integer> c3 = SingleCollection.of(14);
        Collection<Number> c4 = new SingleCollection<Number>(12);
        
        assertEquals(c1, c2);
        assertFalse(c1.equals(c3));
        assertFalse(c1.equals(new Object()));
        assertTrue(c1.equals(c4));
        
        assertEquals(1, c1.size());
        assertFalse(c1.isEmpty());
        assertTrue(c1.contains(12));
        assertFalse(c1.contains(14));
        assertFalse(c1.contains(12L));
        
        assertTrue( c1.containsAll(c2) );
        assertTrue( c1.containsAll(Arrays.asList(12)) );
        assertFalse( c1.containsAll(Arrays.asList(12,14)) );
        
        assertEquals(0, c1.indexOf(12));
        assertEquals(0, c1.lastIndexOf(12));
        assertEquals(-1, c1.indexOf(14));
        assertEquals(-1, c1.lastIndexOf(14));
    }
    
    @Test
    public void testSublist() {
        SingleCollection<Integer> c1 = new SingleCollection<>(12);
        
        assertEquals(Arrays.asList(12), c1.subList(0, 1));
        assertEquals(Collections.emptyList(), c1.subList(1, 1));
        assertEquals(Collections.emptyList(), c1.subList(0, 0));
        
        try {
            c1.subList(0, 2);
            fail("IndexOutOfBoundsException expected");
        } catch(IndexOutOfBoundsException ex) { assertTrue(true); }
        try {
            c1.subList(1, 2);
            fail("IndexOutOfBoundsException expected");
        } catch(IndexOutOfBoundsException ex) { assertTrue(true); }
        try {
            c1.subList(2, 0);
            fail("IndexOutOfBoundsException expected");
        } catch(IndexOutOfBoundsException ex) { assertTrue(true); }
    }
    
    @Test
    public void testArray() {
        SingleCollection<Number> c1 = new SingleCollection<Number>(12);
        
        assertArray(12, Object.class, c1.toArray());
        assertArray(12, Number.class, c1.toArray(new Number[0]));
        assertArray(12, Number.class, c1.toArray(new Number[1]));

        assertArray(12, Integer.class, c1.toArray(new Integer[0]));
        assertArray(12, Integer.class, c1.toArray(new Integer[1]));
        
    }
    
    @Test
    public void testGetSet() {
        SingleCollection<Number> c1 = new SingleCollection<Number>(12);    
        assertEquals(12, c1.get(0));
        try {
            c1.get(4);
            fail("IndexOutOfBoundsException expected");
        } catch(IndexOutOfBoundsException ex) { assertTrue(true); }
        
        assertEquals(12, c1.set(0, 17));
        
        try {
            c1.set(1, 33);
            fail("IndexOutOfBoundsException expected");
        } catch(IndexOutOfBoundsException ex) { assertTrue(true); }
        
        assertEquals(17, c1.get(0));
        assertEquals(c1.value(), c1.get(0));
    }
    
    @Test
    public void testIterator() {
        SingleCollection<Number> c1 = new SingleCollection<Number>(12);   
        
        ListIterator<Number> iterator1 = c1.listIterator(0);
        assertEquals(12, iterator1.next());
        assertFalse(iterator1.hasNext());
        assertTrue(iterator1.hasPrevious());
        assertEquals(12, iterator1.previous());
        
        ListIterator<Number> iterator2 = c1.listIterator();
        assertEquals(12, iterator2.next());
        assertFalse(iterator2.hasNext());
        assertTrue(iterator2.hasPrevious());
        assertEquals(12, iterator2.previous());
        
        ListIterator<Number> iterator3 = c1.listIterator();
        iterator3.next();
        try {
            iterator3.add(6);
            fail("unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        try {
            iterator3.remove();
            fail("unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        try {
            iterator3.set(6);
            fail("unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        try {
            iterator3.next();
            fail("NoSuchElementException expected");
        } catch(NoSuchElementException ex) { assertTrue(true); }
        
        assertEquals(12, iterator3.previous());
        try {
            iterator3.previous();
            fail("NoSuchElementException expected");
        } catch(NoSuchElementException ex) { assertTrue(true); }
    }
    
    private void assertArray(Object value, Class<?> component, Object array) {
        assertEquals(value, ArrayUtils.wrap(array).get(0) );
        assertEquals(1, ArrayUtils.size(array) );
        assertEquals(component, array.getClass().getComponentType() );
    }
    
    @Test
    public void testNoMutability() {
        SingleCollection<Integer> c1 = new SingleCollection<>(12);
        
        try {
            c1.add(12);
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        try {
            c1.add(0,12);
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        try {
            c1.addAll(Arrays.asList(7));
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        try {
            c1.addAll(Collections.<Integer>emptyList());
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        try {
            c1.addAll(0, Arrays.asList(7));
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        
        try {
            c1.clear();
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        
        try {
            c1.remove(0);
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        try {
            c1.remove(7);
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        
        try {
            c1.remove((Integer)12);
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        try {
            c1.remove((Integer)7);
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        
        try {
            c1.removeAll(Arrays.asList(12));
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        try {
            c1.removeAll(Collections.<Integer>emptyList());
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
        try {
            c1.retainAll(Arrays.asList(12));
            fail("Unsupported operation");
        } catch(UnsupportedOperationException ex) { assertTrue(true); }
    }
    
}
