/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.dlect.events.collections;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import static org.dlect.test.helper.DataGeneratorHelper.fillMap;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
*
* @author lee
*/
@RunWith(MockitoJUnitRunner.class)
@SuppressWarnings("unchecked")
public class EventFiringMapTest {
@Mock
private Map<String, String> delegate;
private Map<String, String> map;
@Mock
CollectionEventHelper<Map.Entry<String, String>> helper;
@InjectMocks
private EventFiringMap<String, String> testMockedMapObject;
private EventFiringMap<String, String> testObject;
@Before
public void before() {
map = Maps.newHashMap();
testObject = new EventFiringMap<>(map, helper);
}
private void configureAnswer() {
Answer<Void> helperCheckingAnswer = new AnswerImpl();
doAnswer(helperCheckingAnswer).when(helper).fireAdd(any(Entry.class));
doAnswer(helperCheckingAnswer).when(helper).fireRemove(any(Entry.class));
doAnswer(helperCheckingAnswer).when(helper).fireReplace(any(Entry.class), any(Entry.class));
}
private Entry<String, String> entry(String key, String value) {
return Maps.immutableEntry(key, value);
}
/**
* Test of delegate method, of class EventFiringMap.
*/
@Test
public void testDelegate() {
assertSame(delegate, testMockedMapObject.delegate());
}
/**
* Test of clear method, of class EventFiringMap.
*/
@Test
public void testClear_EmptyMap() {
configureAnswer();
testObject.clear();
verifyZeroInteractions(helper);
}
/**
* Test of clear method, of class EventFiringMap.
*/
@Test
public void testClear_WithItems() {
Map<String, String> toAdd = fillMap(1, 10);
map.putAll(toAdd);
configureAnswer();
testObject.clear();
for (Entry<String, String> entry : toAdd.entrySet()) {
verify(helper).fireRemove(entry);
}
verifyNoMoreInteractions(helper);
}
/**
* Test of put method, of class EventFiringMap.
*/
@Test
public void testPut_NonExisting() {
configureAnswer();
testObject.put("Hello", "World");
verify(helper).fireAdd(entry("Hello", "World"));
verifyNoMoreInteractions(helper);
}
/**
* Test of put method, of class EventFiringMap.
*/
@Test
public void testPut_Existing() {
map.put("Hello", "Old World");
configureAnswer();
testObject.put("Hello", "World");
verify(helper).fireReplace(entry("Hello", "Old World"), entry("Hello", "World"));
verifyNoMoreInteractions(helper);
}
/**
* Test of put method, of class EventFiringMap.
*/
@Test
public void testPut_ExistingNoChange() {
map.put("Hello", "World");
configureAnswer();
testObject.put("Hello", "World");
verifyZeroInteractions(helper);
}
/**
* Test of putAll method, of class EventFiringMap.
*/
@Test
public void testPutAll_NonExisting() {
Map<String, String> toAdd = fillMap(1, 10);
configureAnswer();
testObject.putAll(toAdd);
for (Entry<String, String> entry : toAdd.entrySet()) {
verify(helper).fireAdd(entry);
}
verifyNoMoreInteractions(helper);
}
/**
* Test of putAll method, of class EventFiringMap.
*/
@Test
public void testPutAll_Existing() {
Map<String, String> toAdd = fillMap(1, 10, "", "Old ");
map.putAll(toAdd);
Map<String, String> toUpdate = fillMap(1, 10, "", "New ");
configureAnswer();
testObject.putAll(toUpdate);
for (String k : toAdd.keySet()) {
String old = toAdd.get(k);
String upd = toUpdate.get(k);
verify(helper).fireReplace(entry(k, old), entry(k, upd));
}
verifyNoMoreInteractions(helper);
}
/**
* Test of putAll method, of class EventFiringMap.
*/
@Test
public void testPutAll_ExistingNoChange() {
Map<String, String> toAdd = fillMap(1, 10);
map.putAll(toAdd);
Map<String, String> toUpdate = fillMap(1, 10);
configureAnswer();
testObject.putAll(toUpdate);
verifyZeroInteractions(helper);
}
/**
* Test of remove method, of class EventFiringMap.
*/
@Test
public void testRemove() {
map.put("Hello", "World");
map.put("Hi", "World2");
configureAnswer();
testObject.remove("Hello");
verify(helper).fireRemove(entry("Hello", "World"));
verifyNoMoreInteractions(helper);
}
private class AnswerImpl implements Answer<Void> {
public AnswerImpl() {
}
private Set<Entry<String, String>> prev = copyMap();
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
String name = invocation.getMethod().getName();
if (name.contains("Add")) {
checkAdd(invocation.getArguments()[0]);
} else if (name.contains("Remove")) {
checkRemove(invocation.getArguments()[0]);
} else if (name.contains("Replace")) {
checkReplace(invocation.getArguments()[0], invocation.getArguments()[1]);
} else {
throw new IllegalStateException("Illegal Method Call: " + invocation);
}
prev = copyMap();
return null;
}
private Entry<String, String> assertEntryAndImmutable(Object object) {
assertTrue(object instanceof Entry);
Entry<String, String> e = (Entry<String, String>) object;
try {
try {
e.setValue("New Value - Never before seen prices");
} catch (AssertionError er) {
throw new AssertionError("Set Value ran away and caused an error", er);
}
fail("No exception thrown on set value");
} catch (UnsupportedOperationException ex) {
// No Op.
}
return e;
}
private void checkAdd(Object object) {
assertEquals(prev.size() + 1, map.size());
Entry<String, String> e = assertEntryAndImmutable(object);
Set<Entry<String, String>> copy = copyMap();
copy.removeAll(copyPrev());
assertEquals(1, copy.size());
Entry<String, String> next = copy.iterator().next();
assertEquals(e, next);
assertEquals(e.getKey(), next.getKey());
assertEquals(e.getValue(), next.getValue());
}
private void checkRemove(Object object) {
assertEquals(prev.size() - 1, map.size());
Entry<String, String> e = assertEntryAndImmutable(object);
Set<Entry<String, String>> copy = copyPrev();
copy.removeAll(copyMap());
assertEquals(1, copy.size());
Entry<String, String> next = copy.iterator().next();
assertEquals(e, next);
assertEquals(e.getKey(), next.getKey());
assertEquals(e.getValue(), next.getValue());
}
private void checkReplace(Object oriO, Object replO) {
assertEquals("Map size changed.", prev.size(), map.size());
Entry<String, String> ori = assertEntryAndImmutable(oriO);
Entry<String, String> repl = assertEntryAndImmutable(replO);
assertEquals(ori.getKey(), repl.getKey());
Set<Entry<String, String>> copy = copyPrev();
copy.removeAll(copyMap());
assertEquals("Compare the pair: " + prev + "\nCompare the pair: " + map.entrySet(), 1, copy.size());
Entry<String, String> next = copy.iterator().next();
assertEquals(ori, next);
assertEquals(ori.getKey(), next.getKey());
assertEquals(ori.getValue(), next.getValue());
// \/ NEW VALUE CORRECT \/
copy = copyMap();
copy.removeAll(copyPrev());
assertEquals(1, copy.size());
next = copy.iterator().next();
assertEquals(repl, next);
assertEquals(repl.getKey(), next.getKey());
assertEquals(repl.getValue(), next.getValue());
}
private Set<Entry<String, String>> copyPrev() {
return Sets.newHashSet(prev);
}
private Set<Entry<String, String>> copyMap() {
return Maps.newHashMap(map).entrySet();
}
}
}