/**
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.waveprotocol.wave.model.util;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.waveprotocol.wave.model.wave.ObservableMap;
import org.waveprotocol.wave.model.wave.ObservableMapImpl;
import java.util.Collections;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
/**
* Test case for {@link ObservableMapImpl}.
*
*/
public final class ObservableMapImplTest extends TestCase {
private static class MockListener<K, V> implements ObservableMap.Listener<K, V> {
private final Queue<Pair<K, V>> added = CollectionUtils.createQueue();
private final Queue<Pair<K, V>> removed = CollectionUtils.createQueue();
private final ObservableMap.Listener<K, V> verifier = new ObservableMap.Listener<K, V>() {
@Override
public void onEntryAdded(K key, V value) {
assertEquals(Pair.of(key, value), added.remove());
}
@Override
public void onEntryRemoved(K key, V value) {
assertEquals(Pair.of(key, value), removed.remove());
}
};
@Override
public void onEntryAdded(K key, V value) {
added.add(Pair.of(key, value));
}
@Override
public void onEntryRemoved(K key, V value) {
removed.add(Pair.of(key, value));
}
ObservableMap.Listener<K, V> verify() {
return verifier;
}
void verifyNoMoreInteractions() {
assertTrue(added.isEmpty());
assertTrue(removed.isEmpty());
}
}
private static final Object a = new Object();
private static final Object b = new Object();
private ObservableMapImpl<String, Object> target;
private MockListener<String, Object> listener;
@Override
protected void setUp() {
target = ObservableMapImpl.create();
listener = new MockListener<String, Object>();
}
private static <T> void assertEquals(Set<T> expected, Iterable<T> actual) {
Set<T> actualSet = new HashSet<T>();
for (T x : actual) {
actualSet.add(x);
}
Assert.assertEquals(new HashSet<T>(expected), actualSet);
}
//
// Basic structural tests.
//
public void testPutIsReturnedByGet() {
target.put("a", a);
assertEquals(a, target.get("a"));
}
public void testTwoPutsAreReturnedByTwoGets() {
target.put("a", a);
target.put("b", b);
assertEquals(a, target.get("a"));
assertEquals(b, target.get("b"));
}
public void testPutClobbers() {
target.put("a", new Object());
target.put("a", a);
assertEquals(a, target.get("a"));
}
public void testRemoveIsNotReturnedByGet() {
target.put("a", a);
target.remove("a");
assertNull(target.get("a"));
}
public void testTwoRemovesAreNotReturnedByTwoGets() {
target.put("a", a);
target.put("b", b);
target.remove("a");
target.remove("b");
assertNull(target.get("a"));
assertNull(target.get("b"));
}
public void testRemoveOnlyRemovesOne() {
target.put("a", a);
target.put("b", b);
target.remove("a");
assertEquals(b, target.get("b"));
}
//
// Keys
//
public void testKeyCollectionWithOneKey() {
target.put("a", new Object());
assertEquals(Collections.singleton("a"), target.copyKeys());
}
public void testKeyCollectionWithManyKeys() {
target.put("a", new Object());
target.put("b", new Object());
target.put("c", new Object());
target.put("d", new Object());
assertEquals(CollectionUtils.newHashSet("a", "b", "c", "d"), target.copyKeys());
}
public void testKeyCollectionWithManyKeysAfterMutations() {
target.put("a", new Object());
target.put("b", new Object());
target.put("c", new Object());
target.put("d", new Object());
target.remove("c");
target.remove("d");
target.put("d", new Object());
assertEquals(CollectionUtils.newHashSet("a", "b", "d"), target.copyKeys());
}
//
// Events.
//
public void testSinglePutBroadcastsEvent() {
target.addListener(listener);
target.put("a", a);
listener.verify().onEntryAdded("a", a);
listener.verifyNoMoreInteractions();
}
public void testTwoPutsBroadcastTwoEvents() {
target.addListener(listener);
target.put("a", a);
target.put("b", b);
listener.verify().onEntryAdded("a", a);
listener.verify().onEntryAdded("b", b);
listener.verifyNoMoreInteractions();
}
public void testObserveAfterPutDoesNotBroadcastPriorEvent() {
target.put("a", a);
target.addListener(listener);
target.put("b", b);
listener.verify().onEntryAdded("b", b);
listener.verifyNoMoreInteractions();
}
public void testRemoveBroadcastsEvent() {
target.addListener(listener);
target.put("a", a);
target.remove("a");
listener.verify().onEntryRemoved("a", a);
}
public void testClobberBroadcastsRemoveThenAdd() {
target.put("x", a);
target.addListener(listener);
target.put("x", b);
listener.verify().onEntryRemoved("x", a);
listener.verify().onEntryAdded("x", b);
listener.verifyNoMoreInteractions();
}
}