• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
testConstrainedCollectionLegal()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 
testConstrainedCollectionIllegal()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 
testConstrainedSetLegal()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 
testConstrainedSetIllegal()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 
testConstrainedSortedSetLegal()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 
testConstrainedSortedSetIllegal()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 
testConstrainedListLegal()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 
testConstrainedListRandomAccessFalse()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 
testConstrainedListIllegal()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 
testNefariousAddAll()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    */
onceIterableCollection(final E element)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 }
295