ConstraintsTest.java revision 7dd252788645e940eada959bdde927426e2531c9
1/*
2 * Copyright (C) 2007 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.collect;
18
19import static java.util.Arrays.asList;
20
21import com.google.common.annotations.GwtCompatible;
22import com.google.common.annotations.GwtIncompatible;
23import com.google.common.testing.FluentAsserts;
24import com.google.common.testing.SerializableTester;
25
26import java.util.AbstractCollection;
27import java.util.Collection;
28import java.util.Collections;
29import java.util.Iterator;
30import java.util.List;
31import java.util.ListIterator;
32import java.util.RandomAccess;
33import java.util.Set;
34import java.util.SortedSet;
35
36import junit.framework.TestCase;
37
38/**
39 * Tests for {@code Constraints}.
40 *
41 * @author Mike Bostock
42 * @author Jared Levy
43 */
44@GwtCompatible(emulated = true)
45public class ConstraintsTest extends TestCase {
46
47  private static final String TEST_ELEMENT = "test";
48
49  private static final class TestElementException
50      extends IllegalArgumentException {
51    private static final long serialVersionUID = 0;
52  }
53
54  private static final Constraint<String> TEST_CONSTRAINT
55      = new Constraint<String>() {
56          @Override
57          public String checkElement(String element) {
58            if (TEST_ELEMENT.equals(element)) {
59              throw new TestElementException();
60            }
61            return element;
62          }
63        };
64
65  public void testNotNull() {
66    Constraint<? super String> constraint = Constraints.notNull();
67    assertSame(TEST_ELEMENT, constraint.checkElement(TEST_ELEMENT));
68    try {
69      constraint.checkElement(null);
70      fail("NullPointerException expected");
71    } catch (NullPointerException expected) {}
72    assertEquals("Not null", constraint.toString());
73  }
74
75  public void testConstrainedCollectionLegal() {
76    Collection<String> collection = Lists.newArrayList("foo", "bar");
77    Collection<String> constrained = Constraints.constrainedCollection(
78        collection, TEST_CONSTRAINT);
79    collection.add(TEST_ELEMENT);
80    constrained.add("qux");
81    constrained.addAll(asList("cat", "dog"));
82    /* equals and hashCode aren't defined for Collection */
83    FluentAsserts.assertThat(collection).has().allOf("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
84    FluentAsserts.assertThat(constrained).has()
85        .allOf("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
86  }
87
88  public void testConstrainedCollectionIllegal() {
89    Collection<String> collection = Lists.newArrayList("foo", "bar");
90    Collection<String> constrained = Constraints.constrainedCollection(
91        collection, TEST_CONSTRAINT);
92    try {
93      constrained.add(TEST_ELEMENT);
94      fail("TestElementException expected");
95    } catch (TestElementException expected) {}
96    try {
97      constrained.addAll(asList("baz", TEST_ELEMENT));
98      fail("TestElementException expected");
99    } catch (TestElementException expected) {}
100    FluentAsserts.assertThat(constrained).has().allOf("foo", "bar").inOrder();
101    FluentAsserts.assertThat(collection).has().allOf("foo", "bar").inOrder();
102  }
103
104  public void testConstrainedSetLegal() {
105    Set<String> set = Sets.newLinkedHashSet(asList("foo", "bar"));
106    Set<String> constrained = Constraints.constrainedSet(set, TEST_CONSTRAINT);
107    set.add(TEST_ELEMENT);
108    constrained.add("qux");
109    constrained.addAll(asList("cat", "dog"));
110    assertTrue(set.equals(constrained));
111    assertTrue(constrained.equals(set));
112    assertEquals(set.toString(), constrained.toString());
113    assertEquals(set.hashCode(), constrained.hashCode());
114    FluentAsserts.assertThat(set).has().allOf("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
115    FluentAsserts.assertThat(constrained).has()
116        .allOf("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
117  }
118
119  public void testConstrainedSetIllegal() {
120    Set<String> set = Sets.newLinkedHashSet(asList("foo", "bar"));
121    Set<String> constrained = Constraints.constrainedSet(set, TEST_CONSTRAINT);
122    try {
123      constrained.add(TEST_ELEMENT);
124      fail("TestElementException expected");
125    } catch (TestElementException expected) {}
126    try {
127      constrained.addAll(asList("baz", TEST_ELEMENT));
128      fail("TestElementException expected");
129    } catch (TestElementException expected) {}
130    FluentAsserts.assertThat(constrained).has().allOf("foo", "bar").inOrder();
131    FluentAsserts.assertThat(set).has().allOf("foo", "bar").inOrder();
132  }
133
134  public void testConstrainedSortedSetLegal() {
135    SortedSet<String> sortedSet = Sets.newTreeSet(asList("foo", "bar"));
136    SortedSet<String> constrained = Constraints.constrainedSortedSet(
137        sortedSet, TEST_CONSTRAINT);
138    sortedSet.add(TEST_ELEMENT);
139    constrained.add("qux");
140    constrained.addAll(asList("cat", "dog"));
141    assertTrue(sortedSet.equals(constrained));
142    assertTrue(constrained.equals(sortedSet));
143    assertEquals(sortedSet.toString(), constrained.toString());
144    assertEquals(sortedSet.hashCode(), constrained.hashCode());
145    FluentAsserts.assertThat(sortedSet).has().allOf("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT).inOrder();
146    FluentAsserts.assertThat(constrained).has()
147        .allOf("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT).inOrder();
148    assertNull(constrained.comparator());
149    assertEquals("bar", constrained.first());
150    assertEquals(TEST_ELEMENT, constrained.last());
151  }
152
153  public void testConstrainedSortedSetIllegal() {
154    SortedSet<String> sortedSet = Sets.newTreeSet(asList("foo", "bar"));
155    SortedSet<String> constrained = Constraints.constrainedSortedSet(
156        sortedSet, TEST_CONSTRAINT);
157    try {
158      constrained.add(TEST_ELEMENT);
159      fail("TestElementException expected");
160    } catch (TestElementException expected) {}
161    try {
162      constrained.subSet("bar", "foo").add(TEST_ELEMENT);
163      fail("TestElementException expected");
164    } catch (TestElementException expected) {}
165    try {
166      constrained.headSet("bar").add(TEST_ELEMENT);
167      fail("TestElementException expected");
168    } catch (TestElementException expected) {}
169    try {
170      constrained.tailSet("foo").add(TEST_ELEMENT);
171      fail("TestElementException expected");
172    } catch (TestElementException expected) {}
173    try {
174      constrained.addAll(asList("baz", TEST_ELEMENT));
175      fail("TestElementException expected");
176    } catch (TestElementException expected) {}
177    FluentAsserts.assertThat(constrained).has().allOf("bar", "foo").inOrder();
178    FluentAsserts.assertThat(sortedSet).has().allOf("bar", "foo").inOrder();
179  }
180
181  public void testConstrainedListLegal() {
182    List<String> list = Lists.newArrayList("foo", "bar");
183    List<String> constrained = Constraints.constrainedList(
184        list, TEST_CONSTRAINT);
185    list.add(TEST_ELEMENT);
186    constrained.add("qux");
187    constrained.addAll(asList("cat", "dog"));
188    constrained.add(1, "cow");
189    constrained.addAll(4, asList("box", "fan"));
190    constrained.set(2, "baz");
191    assertTrue(list.equals(constrained));
192    assertTrue(constrained.equals(list));
193    assertEquals(list.toString(), constrained.toString());
194    assertEquals(list.hashCode(), constrained.hashCode());
195    FluentAsserts.assertThat(list).has().allOf(
196        "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
197    FluentAsserts.assertThat(constrained).has().allOf(
198        "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
199    ListIterator<String> iterator = constrained.listIterator();
200    iterator.next();
201    iterator.set("sun");
202    constrained.listIterator(2).add("sky");
203    FluentAsserts.assertThat(list).has().allOf(
204        "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
205    FluentAsserts.assertThat(constrained).has().allOf(
206        "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
207    assertTrue(constrained instanceof RandomAccess);
208  }
209
210  public void testConstrainedListRandomAccessFalse() {
211    List<String> list = Lists.newLinkedList(asList("foo", "bar"));
212    List<String> constrained = Constraints.constrainedList(
213        list, TEST_CONSTRAINT);
214    list.add(TEST_ELEMENT);
215    constrained.add("qux");
216    assertFalse(constrained instanceof RandomAccess);
217  }
218
219  public void testConstrainedListIllegal() {
220    List<String> list = Lists.newArrayList("foo", "bar");
221    List<String> constrained = Constraints.constrainedList(
222        list, TEST_CONSTRAINT);
223    try {
224      constrained.add(TEST_ELEMENT);
225      fail("TestElementException expected");
226    } catch (TestElementException expected) {}
227    try {
228      constrained.listIterator().add(TEST_ELEMENT);
229      fail("TestElementException expected");
230    } catch (TestElementException expected) {}
231    try {
232      constrained.listIterator(1).add(TEST_ELEMENT);
233      fail("TestElementException expected");
234    } catch (TestElementException expected) {}
235    try {
236      constrained.listIterator().set(TEST_ELEMENT);
237      fail("TestElementException expected");
238    } catch (TestElementException expected) {}
239    try {
240      constrained.listIterator(1).set(TEST_ELEMENT);
241      fail("TestElementException expected");
242    } catch (TestElementException expected) {}
243    try {
244      constrained.subList(0, 1).add(TEST_ELEMENT);
245      fail("TestElementException expected");
246    } catch (TestElementException expected) {}
247    try {
248      constrained.add(1, TEST_ELEMENT);
249      fail("TestElementException expected");
250    } catch (TestElementException expected) {}
251    try {
252      constrained.set(1, TEST_ELEMENT);
253      fail("TestElementException expected");
254    } catch (TestElementException expected) {}
255    try {
256      constrained.addAll(asList("baz", TEST_ELEMENT));
257      fail("TestElementException expected");
258    } catch (TestElementException expected) {}
259    try {
260      constrained.addAll(1, asList("baz", TEST_ELEMENT));
261      fail("TestElementException expected");
262    } catch (TestElementException expected) {}
263    FluentAsserts.assertThat(constrained).has().allOf("foo", "bar").inOrder();
264    FluentAsserts.assertThat(list).has().allOf("foo", "bar").inOrder();
265  }
266
267  public void testConstrainedMultisetLegal() {
268    Multiset<String> multiset = HashMultiset.create(asList("foo", "bar"));
269    Multiset<String> constrained = Constraints.constrainedMultiset(
270        multiset, TEST_CONSTRAINT);
271    multiset.add(TEST_ELEMENT);
272    constrained.add("qux");
273    constrained.addAll(asList("cat", "dog"));
274    constrained.add("cow", 2);
275    assertTrue(multiset.equals(constrained));
276    assertTrue(constrained.equals(multiset));
277    assertEquals(multiset.toString(), constrained.toString());
278    assertEquals(multiset.hashCode(), constrained.hashCode());
279    FluentAsserts.assertThat(multiset).has().allOf(
280        "foo", "bar", TEST_ELEMENT, "qux", "cat", "dog", "cow", "cow");
281    FluentAsserts.assertThat(constrained).has().allOf(
282        "foo", "bar", TEST_ELEMENT, "qux", "cat", "dog", "cow", "cow");
283    assertEquals(1, constrained.count("foo"));
284    assertEquals(1, constrained.remove("foo", 3));
285    assertEquals(2, constrained.setCount("cow", 0));
286    FluentAsserts.assertThat(multiset).has().allOf("bar", TEST_ELEMENT, "qux", "cat", "dog");
287    FluentAsserts.assertThat(constrained).has().allOf("bar", TEST_ELEMENT, "qux", "cat", "dog");
288  }
289
290  public void testConstrainedMultisetIllegal() {
291    Multiset<String> multiset = HashMultiset.create(asList("foo", "bar"));
292    Multiset<String> constrained = Constraints.constrainedMultiset(
293        multiset, TEST_CONSTRAINT);
294    try {
295      constrained.add(TEST_ELEMENT);
296      fail("TestElementException expected");
297    } catch (TestElementException expected) {}
298    try {
299      constrained.add(TEST_ELEMENT, 2);
300      fail("TestElementException expected");
301    } catch (TestElementException expected) {}
302    try {
303      constrained.addAll(asList("baz", TEST_ELEMENT));
304      fail("TestElementException expected");
305    } catch (TestElementException expected) {}
306    FluentAsserts.assertThat(constrained).has().allOf("foo", "bar");
307    FluentAsserts.assertThat(multiset).has().allOf("foo", "bar");
308  }
309
310  public void testNefariousAddAll() {
311    List<String> list = Lists.newArrayList("foo", "bar");
312    List<String> constrained = Constraints.constrainedList(
313        list, TEST_CONSTRAINT);
314    Collection<String> onceIterable = onceIterableCollection("baz");
315    constrained.addAll(onceIterable);
316    FluentAsserts.assertThat(constrained).has().allOf("foo", "bar", "baz").inOrder();
317    FluentAsserts.assertThat(list).has().allOf("foo", "bar", "baz").inOrder();
318  }
319
320  /**
321   * Returns a "nefarious" collection, which permits only one call to
322   * iterator(). This verifies that the constrained collection uses a defensive
323   * copy instead of potentially checking the elements in one snapshot and
324   * adding the elements from another.
325   *
326   * @param element the element to be contained in the collection
327   */
328  static <E> Collection<E> onceIterableCollection(final E element) {
329    return new AbstractCollection<E>() {
330      boolean iteratorCalled;
331      @Override public int size() {
332        /*
333         * We could make the collection empty, but that seems more likely to
334         * trigger special cases (so maybe we should test both empty and
335         * nonempty...).
336         */
337        return 1;
338      }
339      @Override public Iterator<E> iterator() {
340        assertFalse("Expected only one call to iterator()", iteratorCalled);
341        iteratorCalled = true;
342        return Collections.singleton(element).iterator();
343      }
344    };
345  }
346
347  @GwtIncompatible("SerializableTester")
348  public void testSerialization() {
349    // TODO: Test serialization of constrained collections.
350    assertSame(Constraints.notNull(),
351        SerializableTester.reserialize(Constraints.notNull()));
352  }
353}
354