/** * Copyright 2008 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.TestCase; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.ConcurrentModificationException; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Test case for {@link ConcurrentSet}. * */ public class ConcurrentSetTest extends TestCase { /** Instance being tested. Created in {@link #setUp()}. */ private ConcurrentSet<String> set; /** Dummy items used in the tests. */ private String a; private String b; private String c; private String d; @Override protected void setUp() throws Exception { set = ConcurrentSet.create(); a = "a"; b = "b"; c = "c"; d = "d"; } /** * Creates a list of items in the order returned by iterating over a * ConcurrentSet (this is used to ensure set semantics are maintained). * * @param xs a ConcurrentSet * @return a list containing the items returned by iterating over {@code xs}. */ private static <T> List<T> asList(ConcurrentSet<T> xs) { List<T> list = new ArrayList<T>(); for (T x : xs) { list.add(x); } return list; } /** * Creates a set containing the items returned by iterating over a * ConcurrentSet (this is used to compare a ConcurrentSet to a Set, since * ConcurrentSet does not implement equality with Sets). * * @param xs a ConcurrentSet * @return a set containing the items returned by iterating over {@code xs}. */ private static <T> Set<T> asSet(ConcurrentSet<T> xs) { return new HashSet<T>(asList(xs)); } /** * Creates a Set. * * @param xs items to put in the set * @return a set containing {@code xs}. */ private static <T> Set<T> setOf(T ... xs) { return new HashSet<T>(Arrays.asList(xs)); } public void testBasicAddAndRemove() { set.add(a); assertEquals("initial add failed", setOf(a), asSet(set)); set.add(b); assertEquals("second add failed", setOf(a, b), asSet(set)); set.add(b); assertEquals("b added twice", 2, asList(set).size()); set.remove(a); assertEquals("initial remove failed", setOf(b), asSet(set)); set.remove(b); assertEquals("second remove failed", Collections.<String>emptySet(), asSet(set)); } public void testAddWhileLockedDoesNotCauseCme() { set.add(a); set.add(b); set.add(c); set.lock(); try { // We attempt to add d on every iteration. for (String x : set) { set.add(d); } } catch (ConcurrentModificationException e) { fail("addition during iteration caused CME"); } set.unlock(); } public void testRemoveWhileLockedDoesNotCauseCme() { set.add(a); set.add(b); set.add(c); set.add(d); set.lock(); try { // Removals to attempt on every iteration. String [] removals = new String [] {b, d, c, a}; int toRemove = 0; for (String x : set) { set.remove(removals[toRemove++]); } } catch (ConcurrentModificationException e) { fail("removal during iteration caused CME"); } set.unlock(); } public void testAddIsDelayedWhileLocked() { set.add(a); set.add(b); set.lock(); // try to add c, and check that it should not go into the iterable collection yet set.add(c); assertEquals(setOf(a, b), asSet(set)); // try again set.add(c); assertEquals(setOf(a, b), asSet(set)); // try again with d set.add(d); assertEquals(setOf(a, b), asSet(set)); // unlock, and test that c and d have been added, but only once each set.unlock(); assertEquals("wrong size", 4, asList(set).size()); assertEquals("c and/or d were not added", setOf(a, b, c, d), asSet(set)); } public void testRemoveIsDelayedWhileLocked() { set.add(a); set.add(b); set.add(c); set.add(d); set.lock(); // try to remove c, and check that it should still be in the iterable collection yet set.remove(c); assertEquals(setOf(a, b, c, d), asSet(set)); // try again with d set.remove(d); assertEquals(setOf(a, b, c, d), asSet(set)); // unlock, and test that c and d get removed. set.unlock(); assertEquals("wrong size", 2, asList(set).size()); assertEquals("c and/or d were not removed", setOf(a, b), asSet(set)); } public void testAddAfterRemoveWhileLockedHasNoEffect() { set.add(a); set.add(b); set.add(c); set.lock(); set.remove(b); set.add(b); set.unlock(); assertEquals(setOf(a, b, c), asSet(set)); } public void testRemoveAfterAddWhileLockedHasNoEffect() { set.add(a); set.add(b); set.lock(); set.add(c); set.remove(c); set.unlock(); assertEquals(setOf(a, b), asSet(set)); } }