View Javadoc
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  
17  package com.google.common.collect;
18  
19  import static com.google.common.truth.Truth.assertThat;
20  import static java.util.Arrays.asList;
21  
22  import com.google.common.annotations.GwtCompatible;
23  
24  import junit.framework.TestCase;
25  
26  import java.util.AbstractCollection;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.ListIterator;
32  import java.util.RandomAccess;
33  import java.util.Set;
34  import java.util.SortedSet;
35  
36  /**
37   * Tests for {@code Constraints}.
38   *
39   * @author Mike Bostock
40   * @author Jared Levy
41   */
42  @GwtCompatible
43  public class ConstraintsTest extends TestCase {
44  
45    private static final String TEST_ELEMENT = "test";
46  
47    private static final class TestElementException
48        extends IllegalArgumentException {
49      private static final long serialVersionUID = 0;
50    }
51  
52    private static final Constraint<String> TEST_CONSTRAINT
53        = new Constraint<String>() {
54            @Override
55            public String checkElement(String element) {
56              if (TEST_ELEMENT.equals(element)) {
57                throw new TestElementException();
58              }
59              return element;
60            }
61          };
62  
63    public void testConstrainedCollectionLegal() {
64      Collection<String> collection = Lists.newArrayList("foo", "bar");
65      Collection<String> constrained = Constraints.constrainedCollection(
66          collection, TEST_CONSTRAINT);
67      collection.add(TEST_ELEMENT);
68      constrained.add("qux");
69      constrained.addAll(asList("cat", "dog"));
70      /* equals and hashCode aren't defined for Collection */
71      assertThat(collection).has()
72          .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
73      assertThat(constrained).has()
74          .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
75    }
76  
77    public void testConstrainedCollectionIllegal() {
78      Collection<String> collection = Lists.newArrayList("foo", "bar");
79      Collection<String> constrained = Constraints.constrainedCollection(
80          collection, TEST_CONSTRAINT);
81      try {
82        constrained.add(TEST_ELEMENT);
83        fail("TestElementException expected");
84      } catch (TestElementException expected) {}
85      try {
86        constrained.addAll(asList("baz", TEST_ELEMENT));
87        fail("TestElementException expected");
88      } catch (TestElementException expected) {}
89      assertThat(constrained).has().exactly("foo", "bar").inOrder();
90      assertThat(collection).has().exactly("foo", "bar").inOrder();
91    }
92  
93    public void testConstrainedSetLegal() {
94      Set<String> set = Sets.newLinkedHashSet(asList("foo", "bar"));
95      Set<String> constrained = Constraints.constrainedSet(set, TEST_CONSTRAINT);
96      set.add(TEST_ELEMENT);
97      constrained.add("qux");
98      constrained.addAll(asList("cat", "dog"));
99      assertTrue(set.equals(constrained));
100     assertTrue(constrained.equals(set));
101     assertEquals(set.toString(), constrained.toString());
102     assertEquals(set.hashCode(), constrained.hashCode());
103     assertThat(set).has().exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
104     assertThat(constrained).has()
105         .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
106   }
107 
108   public void testConstrainedSetIllegal() {
109     Set<String> set = Sets.newLinkedHashSet(asList("foo", "bar"));
110     Set<String> constrained = Constraints.constrainedSet(set, TEST_CONSTRAINT);
111     try {
112       constrained.add(TEST_ELEMENT);
113       fail("TestElementException expected");
114     } catch (TestElementException expected) {}
115     try {
116       constrained.addAll(asList("baz", TEST_ELEMENT));
117       fail("TestElementException expected");
118     } catch (TestElementException expected) {}
119     assertThat(constrained).has().exactly("foo", "bar").inOrder();
120     assertThat(set).has().exactly("foo", "bar").inOrder();
121   }
122 
123   public void testConstrainedSortedSetLegal() {
124     SortedSet<String> sortedSet = Sets.newTreeSet(asList("foo", "bar"));
125     SortedSet<String> constrained = Constraints.constrainedSortedSet(
126         sortedSet, TEST_CONSTRAINT);
127     sortedSet.add(TEST_ELEMENT);
128     constrained.add("qux");
129     constrained.addAll(asList("cat", "dog"));
130     assertTrue(sortedSet.equals(constrained));
131     assertTrue(constrained.equals(sortedSet));
132     assertEquals(sortedSet.toString(), constrained.toString());
133     assertEquals(sortedSet.hashCode(), constrained.hashCode());
134     assertThat(sortedSet).has().exactly("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT).inOrder();
135     assertThat(constrained).has()
136         .exactly("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT).inOrder();
137     assertNull(constrained.comparator());
138     assertEquals("bar", constrained.first());
139     assertEquals(TEST_ELEMENT, constrained.last());
140   }
141 
142   public void testConstrainedSortedSetIllegal() {
143     SortedSet<String> sortedSet = Sets.newTreeSet(asList("foo", "bar"));
144     SortedSet<String> constrained = Constraints.constrainedSortedSet(
145         sortedSet, TEST_CONSTRAINT);
146     try {
147       constrained.add(TEST_ELEMENT);
148       fail("TestElementException expected");
149     } catch (TestElementException expected) {}
150     try {
151       constrained.subSet("bar", "foo").add(TEST_ELEMENT);
152       fail("TestElementException expected");
153     } catch (TestElementException expected) {}
154     try {
155       constrained.headSet("bar").add(TEST_ELEMENT);
156       fail("TestElementException expected");
157     } catch (TestElementException expected) {}
158     try {
159       constrained.tailSet("foo").add(TEST_ELEMENT);
160       fail("TestElementException expected");
161     } catch (TestElementException expected) {}
162     try {
163       constrained.addAll(asList("baz", TEST_ELEMENT));
164       fail("TestElementException expected");
165     } catch (TestElementException expected) {}
166     assertThat(constrained).has().exactly("bar", "foo").inOrder();
167     assertThat(sortedSet).has().exactly("bar", "foo").inOrder();
168   }
169 
170   public void testConstrainedListLegal() {
171     List<String> list = Lists.newArrayList("foo", "bar");
172     List<String> constrained = Constraints.constrainedList(
173         list, TEST_CONSTRAINT);
174     list.add(TEST_ELEMENT);
175     constrained.add("qux");
176     constrained.addAll(asList("cat", "dog"));
177     constrained.add(1, "cow");
178     constrained.addAll(4, asList("box", "fan"));
179     constrained.set(2, "baz");
180     assertTrue(list.equals(constrained));
181     assertTrue(constrained.equals(list));
182     assertEquals(list.toString(), constrained.toString());
183     assertEquals(list.hashCode(), constrained.hashCode());
184     assertThat(list).has().exactly(
185         "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
186     assertThat(constrained).has().exactly(
187         "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
188     ListIterator<String> iterator = constrained.listIterator();
189     iterator.next();
190     iterator.set("sun");
191     constrained.listIterator(2).add("sky");
192     assertThat(list).has().exactly(
193         "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
194     assertThat(constrained).has().exactly(
195         "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
196     assertTrue(constrained instanceof RandomAccess);
197   }
198 
199   public void testConstrainedListRandomAccessFalse() {
200     List<String> list = Lists.newLinkedList(asList("foo", "bar"));
201     List<String> constrained = Constraints.constrainedList(
202         list, TEST_CONSTRAINT);
203     list.add(TEST_ELEMENT);
204     constrained.add("qux");
205     assertFalse(constrained instanceof RandomAccess);
206   }
207 
208   public void testConstrainedListIllegal() {
209     List<String> list = Lists.newArrayList("foo", "bar");
210     List<String> constrained = Constraints.constrainedList(
211         list, TEST_CONSTRAINT);
212     try {
213       constrained.add(TEST_ELEMENT);
214       fail("TestElementException expected");
215     } catch (TestElementException expected) {}
216     try {
217       constrained.listIterator().add(TEST_ELEMENT);
218       fail("TestElementException expected");
219     } catch (TestElementException expected) {}
220     try {
221       constrained.listIterator(1).add(TEST_ELEMENT);
222       fail("TestElementException expected");
223     } catch (TestElementException expected) {}
224     try {
225       constrained.listIterator().set(TEST_ELEMENT);
226       fail("TestElementException expected");
227     } catch (TestElementException expected) {}
228     try {
229       constrained.listIterator(1).set(TEST_ELEMENT);
230       fail("TestElementException expected");
231     } catch (TestElementException expected) {}
232     try {
233       constrained.subList(0, 1).add(TEST_ELEMENT);
234       fail("TestElementException expected");
235     } catch (TestElementException expected) {}
236     try {
237       constrained.add(1, TEST_ELEMENT);
238       fail("TestElementException expected");
239     } catch (TestElementException expected) {}
240     try {
241       constrained.set(1, TEST_ELEMENT);
242       fail("TestElementException expected");
243     } catch (TestElementException expected) {}
244     try {
245       constrained.addAll(asList("baz", TEST_ELEMENT));
246       fail("TestElementException expected");
247     } catch (TestElementException expected) {}
248     try {
249       constrained.addAll(1, asList("baz", TEST_ELEMENT));
250       fail("TestElementException expected");
251     } catch (TestElementException expected) {}
252     assertThat(constrained).has().exactly("foo", "bar").inOrder();
253     assertThat(list).has().exactly("foo", "bar").inOrder();
254   }
255 
256   public void testNefariousAddAll() {
257     List<String> list = Lists.newArrayList("foo", "bar");
258     List<String> constrained = Constraints.constrainedList(
259         list, TEST_CONSTRAINT);
260     Collection<String> onceIterable = onceIterableCollection("baz");
261     constrained.addAll(onceIterable);
262     assertThat(constrained).has().exactly("foo", "bar", "baz").inOrder();
263     assertThat(list).has().exactly("foo", "bar", "baz").inOrder();
264   }
265 
266   /**
267    * Returns a "nefarious" collection, which permits only one call to
268    * iterator(). This verifies that the constrained collection uses a defensive
269    * copy instead of potentially checking the elements in one snapshot and
270    * adding the elements from another.
271    *
272    * @param element the element to be contained in the collection
273    */
274   static <E> Collection<E> onceIterableCollection(final E element) {
275     return new AbstractCollection<E>() {
276       boolean iteratorCalled;
277       @Override public int size() {
278         /*
279          * We could make the collection empty, but that seems more likely to
280          * trigger special cases (so maybe we should test both empty and
281          * nonempty...).
282          */
283         return 1;
284       }
285       @Override public Iterator<E> iterator() {
286         assertFalse("Expected only one call to iterator()", iteratorCalled);
287         iteratorCalled = true;
288         return Collections.singleton(element).iterator();
289       }
290     };
291   }
292 
293   // TODO: Test serialization of constrained collections.
294 }