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