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

import java.util.*;
import java.util.Map.Entry;
import static junit.framework.Assert.*;
import net.ranides.assira.collection.SetUtils;
import net.ranides.assira.text.Strings;
import org.junit.Test;

/**
 *
 * @author ranides
 */
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
public class MapAdapterTest {
    private static final String SHOULD_BE_UNSUPPORTED = "UnsupportedOperationException expected";
    
    Map<String,Float> data = new HashMap<String, Float>() {{
        put("zero", 0.0f);
        put("one",  1.0f);
        put("two",  2.0f);
        put("three", 3.0f);
        put("four", 4.0f);
        put("half", 0.5f);
        put("pi", 3.14f);
    }};
    
    static class BasicTextAdapter extends MapAdapter<String, Float, String> {
        
        BasicTextAdapter(Map<String,Float> source) {
            super(source);
        }

        @Override
        public String apply(Entry<String, Float> source) {
            return Strings.or( source.getValue() );
        }
        
    }
    
    public MapAdapterTest() {
    }

    @Test
    public void testSize() {
        Map<String,Float> source = new HashMap<>(data);
        Map<String,String> target = new BasicTextAdapter(source);
        assertEquals(7, target.size());
    }

    @Test
    public void testIsEmpty() {
        Map<String,String> target = new BasicTextAdapter( new HashMap<>(data) );
        Map<String,String> empty = new BasicTextAdapter( new HashMap<String, Float>() );
        
        assertFalse(target.isEmpty());
        assertTrue(empty.isEmpty());
    }

    @Test
    public void testContainsKey() {
        Map<String,String> target = new BasicTextAdapter( new HashMap<>(data) );
        
        assertTrue(target.containsKey("one"));
        assertTrue(target.containsKey("pi"));
        assertFalse(target.containsKey("uka"));
    }

    @Test
    public void testContainsValue() {
        Map<String,String> target = new BasicTextAdapter( new HashMap<>(data) );
        
        assertTrue(target.containsValue("1.0"));
        assertTrue(target.containsValue("2.0"));
        assertTrue(target.containsValue("0.5"));
        assertTrue(target.containsValue("3.14"));
        
        assertFalse(target.containsValue("6.0"));
        assertFalse(target.containsValue("99.0"));
        assertFalse(target.containsValue("1.1"));
    }

    @Test
    public void testGet() {
        Map<String,String> target = new BasicTextAdapter( new HashMap<>(data) );
        
        assertEquals( "1.0", target.get("one") );
        assertEquals( "0.5", target.get("half") );
        assertNull( target.get("ea") );
    }

    @Test
    public void testPut() {
        Map<String,String> target = new BasicTextAdapter( new HashMap<>(data) );
        try {
            target.put("pi", "3.1415");
            fail(SHOULD_BE_UNSUPPORTED);
        } catch(UnsupportedOperationException cause) {
            assertTrue(true);
        }
        
        try {
            target.put("other", "3.1415");
            fail(SHOULD_BE_UNSUPPORTED);
        } catch(UnsupportedOperationException cause) {
            assertTrue(true);
        }
    }

    @Test
    public void testRemove() {
        Map<String, Float> source = new HashMap<>(data);
        Map<String,String> target = new BasicTextAdapter(source);
        
        assertTrue(source.containsKey("one"));
        assertTrue(target.containsKey("one"));
        
        assertTrue(source.containsKey("two"));
        assertTrue(target.containsKey("two"));
        
        target.remove("one");
        source.remove("two");
                
        assertFalse(source.containsKey("one"));
        assertFalse(target.containsKey("one"));
        
        assertFalse(source.containsKey("two"));
        assertFalse(target.containsKey("two"));
        
        
    }

    @Test
    public void testPutAll() {
        Map<String,String> target = new BasicTextAdapter( new HashMap<>(data) );
        
        target.putAll(new HashMap<String, String>());
        
        try {
            target.putAll(new HashMap<String, String>(){{put("new","0.0"); }});
            fail(SHOULD_BE_UNSUPPORTED);
        } catch(UnsupportedOperationException cause) {
            assertTrue(true);
        }
    }

    @Test
    public void testClear() {
        Map<String, Float> source = new HashMap<>(data);
        Map<String,String> target = new BasicTextAdapter(source);
        
        assertEquals(7, source.size());
        assertEquals(7, target.size());
        
        target.clear();
        
        assertEquals(0, source.size());
        assertEquals(0, target.size());
    }

    @Test
    public void testKeySet() {
        Map<String,String> target = new BasicTextAdapter( new HashMap<>(data) );
        
        assertEquals( SetUtils.asHashSet("one", "two", "zero", "three", "four", "pi", "half"), target.keySet() );
    }

    @Test
    public void testValues() {
        Map<String,String> target = new BasicTextAdapter( new HashMap<>(data) );
        Set<String> expected = SetUtils.asHashSet("1.0","2.0","3.0","4.0","0.5","3.14","0.0");
        
        assertTrue( expected.containsAll(target.values()) );
        assertTrue( target.values().containsAll(expected) );
    }

    @Test
    public void testEntrySet() {
        Map<String,String> target = new BasicTextAdapter( new HashMap<>(data) );
        Set<String> keys = new HashSet<>();
        Set<String> vals = new HashSet<>();

        for(Entry<String,String> item : target.entrySet()) {
            keys.add(item.getKey());
            vals.add(item.getValue());
        }
        
        assertEquals( SetUtils.asHashSet("one", "two", "zero", "three", "four", "pi", "half"), keys );
        assertEquals( SetUtils.asHashSet("1.0","2.0","3.0","4.0","0.5","3.14","0.0"), vals );
    }

}
