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; 20import static org.truth0.Truth.ASSERT; 21 22import com.google.common.annotations.GwtCompatible; 23 24import junit.framework.TestCase; 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 36/** 37 * Tests for {@code Constraints}. 38 * 39 * @author Mike Bostock 40 * @author Jared Levy 41 */ 42@GwtCompatible(emulated = true) 43public 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 testNotNull() { 64 Constraint<? super String> constraint = Constraints.notNull(); 65 assertSame(TEST_ELEMENT, constraint.checkElement(TEST_ELEMENT)); 66 try { 67 constraint.checkElement(null); 68 fail("NullPointerException expected"); 69 } catch (NullPointerException expected) {} 70 assertEquals("Not null", constraint.toString()); 71 } 72 73 public void testConstrainedCollectionLegal() { 74 Collection<String> collection = Lists.newArrayList("foo", "bar"); 75 Collection<String> constrained = Constraints.constrainedCollection( 76 collection, TEST_CONSTRAINT); 77 collection.add(TEST_ELEMENT); 78 constrained.add("qux"); 79 constrained.addAll(asList("cat", "dog")); 80 /* equals and hashCode aren't defined for Collection */ 81 ASSERT.that(collection).has() 82 .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder(); 83 ASSERT.that(constrained).has() 84 .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder(); 85 } 86 87 public void testConstrainedCollectionIllegal() { 88 Collection<String> collection = Lists.newArrayList("foo", "bar"); 89 Collection<String> constrained = Constraints.constrainedCollection( 90 collection, TEST_CONSTRAINT); 91 try { 92 constrained.add(TEST_ELEMENT); 93 fail("TestElementException expected"); 94 } catch (TestElementException expected) {} 95 try { 96 constrained.addAll(asList("baz", TEST_ELEMENT)); 97 fail("TestElementException expected"); 98 } catch (TestElementException expected) {} 99 ASSERT.that(constrained).has().exactly("foo", "bar").inOrder(); 100 ASSERT.that(collection).has().exactly("foo", "bar").inOrder(); 101 } 102 103 public void testConstrainedSetLegal() { 104 Set<String> set = Sets.newLinkedHashSet(asList("foo", "bar")); 105 Set<String> constrained = Constraints.constrainedSet(set, TEST_CONSTRAINT); 106 set.add(TEST_ELEMENT); 107 constrained.add("qux"); 108 constrained.addAll(asList("cat", "dog")); 109 assertTrue(set.equals(constrained)); 110 assertTrue(constrained.equals(set)); 111 assertEquals(set.toString(), constrained.toString()); 112 assertEquals(set.hashCode(), constrained.hashCode()); 113 ASSERT.that(set).has().exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder(); 114 ASSERT.that(constrained).has() 115 .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder(); 116 } 117 118 public void testConstrainedSetIllegal() { 119 Set<String> set = Sets.newLinkedHashSet(asList("foo", "bar")); 120 Set<String> constrained = Constraints.constrainedSet(set, TEST_CONSTRAINT); 121 try { 122 constrained.add(TEST_ELEMENT); 123 fail("TestElementException expected"); 124 } catch (TestElementException expected) {} 125 try { 126 constrained.addAll(asList("baz", TEST_ELEMENT)); 127 fail("TestElementException expected"); 128 } catch (TestElementException expected) {} 129 ASSERT.that(constrained).has().exactly("foo", "bar").inOrder(); 130 ASSERT.that(set).has().exactly("foo", "bar").inOrder(); 131 } 132 133 public void testConstrainedSortedSetLegal() { 134 SortedSet<String> sortedSet = Sets.newTreeSet(asList("foo", "bar")); 135 SortedSet<String> constrained = Constraints.constrainedSortedSet( 136 sortedSet, TEST_CONSTRAINT); 137 sortedSet.add(TEST_ELEMENT); 138 constrained.add("qux"); 139 constrained.addAll(asList("cat", "dog")); 140 assertTrue(sortedSet.equals(constrained)); 141 assertTrue(constrained.equals(sortedSet)); 142 assertEquals(sortedSet.toString(), constrained.toString()); 143 assertEquals(sortedSet.hashCode(), constrained.hashCode()); 144 ASSERT.that(sortedSet).has().exactly("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT).inOrder(); 145 ASSERT.that(constrained).has() 146 .exactly("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT).inOrder(); 147 assertNull(constrained.comparator()); 148 assertEquals("bar", constrained.first()); 149 assertEquals(TEST_ELEMENT, constrained.last()); 150 } 151 152 public void testConstrainedSortedSetIllegal() { 153 SortedSet<String> sortedSet = Sets.newTreeSet(asList("foo", "bar")); 154 SortedSet<String> constrained = Constraints.constrainedSortedSet( 155 sortedSet, TEST_CONSTRAINT); 156 try { 157 constrained.add(TEST_ELEMENT); 158 fail("TestElementException expected"); 159 } catch (TestElementException expected) {} 160 try { 161 constrained.subSet("bar", "foo").add(TEST_ELEMENT); 162 fail("TestElementException expected"); 163 } catch (TestElementException expected) {} 164 try { 165 constrained.headSet("bar").add(TEST_ELEMENT); 166 fail("TestElementException expected"); 167 } catch (TestElementException expected) {} 168 try { 169 constrained.tailSet("foo").add(TEST_ELEMENT); 170 fail("TestElementException expected"); 171 } catch (TestElementException expected) {} 172 try { 173 constrained.addAll(asList("baz", TEST_ELEMENT)); 174 fail("TestElementException expected"); 175 } catch (TestElementException expected) {} 176 ASSERT.that(constrained).has().exactly("bar", "foo").inOrder(); 177 ASSERT.that(sortedSet).has().exactly("bar", "foo").inOrder(); 178 } 179 180 public void testConstrainedListLegal() { 181 List<String> list = Lists.newArrayList("foo", "bar"); 182 List<String> constrained = Constraints.constrainedList( 183 list, TEST_CONSTRAINT); 184 list.add(TEST_ELEMENT); 185 constrained.add("qux"); 186 constrained.addAll(asList("cat", "dog")); 187 constrained.add(1, "cow"); 188 constrained.addAll(4, asList("box", "fan")); 189 constrained.set(2, "baz"); 190 assertTrue(list.equals(constrained)); 191 assertTrue(constrained.equals(list)); 192 assertEquals(list.toString(), constrained.toString()); 193 assertEquals(list.hashCode(), constrained.hashCode()); 194 ASSERT.that(list).has().exactly( 195 "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder(); 196 ASSERT.that(constrained).has().exactly( 197 "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder(); 198 ListIterator<String> iterator = constrained.listIterator(); 199 iterator.next(); 200 iterator.set("sun"); 201 constrained.listIterator(2).add("sky"); 202 ASSERT.that(list).has().exactly( 203 "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder(); 204 ASSERT.that(constrained).has().exactly( 205 "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder(); 206 assertTrue(constrained instanceof RandomAccess); 207 } 208 209 public void testConstrainedListRandomAccessFalse() { 210 List<String> list = Lists.newLinkedList(asList("foo", "bar")); 211 List<String> constrained = Constraints.constrainedList( 212 list, TEST_CONSTRAINT); 213 list.add(TEST_ELEMENT); 214 constrained.add("qux"); 215 assertFalse(constrained instanceof RandomAccess); 216 } 217 218 public void testConstrainedListIllegal() { 219 List<String> list = Lists.newArrayList("foo", "bar"); 220 List<String> constrained = Constraints.constrainedList( 221 list, TEST_CONSTRAINT); 222 try { 223 constrained.add(TEST_ELEMENT); 224 fail("TestElementException expected"); 225 } catch (TestElementException expected) {} 226 try { 227 constrained.listIterator().add(TEST_ELEMENT); 228 fail("TestElementException expected"); 229 } catch (TestElementException expected) {} 230 try { 231 constrained.listIterator(1).add(TEST_ELEMENT); 232 fail("TestElementException expected"); 233 } catch (TestElementException expected) {} 234 try { 235 constrained.listIterator().set(TEST_ELEMENT); 236 fail("TestElementException expected"); 237 } catch (TestElementException expected) {} 238 try { 239 constrained.listIterator(1).set(TEST_ELEMENT); 240 fail("TestElementException expected"); 241 } catch (TestElementException expected) {} 242 try { 243 constrained.subList(0, 1).add(TEST_ELEMENT); 244 fail("TestElementException expected"); 245 } catch (TestElementException expected) {} 246 try { 247 constrained.add(1, TEST_ELEMENT); 248 fail("TestElementException expected"); 249 } catch (TestElementException expected) {} 250 try { 251 constrained.set(1, TEST_ELEMENT); 252 fail("TestElementException expected"); 253 } catch (TestElementException expected) {} 254 try { 255 constrained.addAll(asList("baz", TEST_ELEMENT)); 256 fail("TestElementException expected"); 257 } catch (TestElementException expected) {} 258 try { 259 constrained.addAll(1, asList("baz", TEST_ELEMENT)); 260 fail("TestElementException expected"); 261 } catch (TestElementException expected) {} 262 ASSERT.that(constrained).has().exactly("foo", "bar").inOrder(); 263 ASSERT.that(list).has().exactly("foo", "bar").inOrder(); 264 } 265 266 public void testConstrainedMultisetLegal() { 267 Multiset<String> multiset = HashMultiset.create(asList("foo", "bar")); 268 Multiset<String> constrained = Constraints.constrainedMultiset( 269 multiset, TEST_CONSTRAINT); 270 multiset.add(TEST_ELEMENT); 271 constrained.add("qux"); 272 constrained.addAll(asList("cat", "dog")); 273 constrained.add("cow", 2); 274 assertTrue(multiset.equals(constrained)); 275 assertTrue(constrained.equals(multiset)); 276 assertEquals(multiset.toString(), constrained.toString()); 277 assertEquals(multiset.hashCode(), constrained.hashCode()); 278 ASSERT.that(multiset).has().exactly( 279 "foo", "bar", TEST_ELEMENT, "qux", "cat", "dog", "cow", "cow"); 280 ASSERT.that(constrained).has().exactly( 281 "foo", "bar", TEST_ELEMENT, "qux", "cat", "dog", "cow", "cow"); 282 assertEquals(1, constrained.count("foo")); 283 assertEquals(1, constrained.remove("foo", 3)); 284 assertEquals(2, constrained.setCount("cow", 0)); 285 ASSERT.that(multiset).has().exactly("bar", TEST_ELEMENT, "qux", "cat", "dog"); 286 ASSERT.that(constrained).has().exactly("bar", TEST_ELEMENT, "qux", "cat", "dog"); 287 } 288 289 public void testConstrainedMultisetIllegal() { 290 Multiset<String> multiset = HashMultiset.create(asList("foo", "bar")); 291 Multiset<String> constrained = Constraints.constrainedMultiset( 292 multiset, TEST_CONSTRAINT); 293 try { 294 constrained.add(TEST_ELEMENT); 295 fail("TestElementException expected"); 296 } catch (TestElementException expected) {} 297 try { 298 constrained.add(TEST_ELEMENT, 2); 299 fail("TestElementException expected"); 300 } catch (TestElementException expected) {} 301 try { 302 constrained.addAll(asList("baz", TEST_ELEMENT)); 303 fail("TestElementException expected"); 304 } catch (TestElementException expected) {} 305 ASSERT.that(constrained).has().exactly("foo", "bar"); 306 ASSERT.that(multiset).has().exactly("foo", "bar"); 307 } 308 309 public void testNefariousAddAll() { 310 List<String> list = Lists.newArrayList("foo", "bar"); 311 List<String> constrained = Constraints.constrainedList( 312 list, TEST_CONSTRAINT); 313 Collection<String> onceIterable = onceIterableCollection("baz"); 314 constrained.addAll(onceIterable); 315 ASSERT.that(constrained).has().exactly("foo", "bar", "baz").inOrder(); 316 ASSERT.that(list).has().exactly("foo", "bar", "baz").inOrder(); 317 } 318 319 /** 320 * Returns a "nefarious" collection, which permits only one call to 321 * iterator(). This verifies that the constrained collection uses a defensive 322 * copy instead of potentially checking the elements in one snapshot and 323 * adding the elements from another. 324 * 325 * @param element the element to be contained in the collection 326 */ 327 static <E> Collection<E> onceIterableCollection(final E element) { 328 return new AbstractCollection<E>() { 329 boolean iteratorCalled; 330 @Override public int size() { 331 /* 332 * We could make the collection empty, but that seems more likely to 333 * trigger special cases (so maybe we should test both empty and 334 * nonempty...). 335 */ 336 return 1; 337 } 338 @Override public Iterator<E> iterator() { 339 assertFalse("Expected only one call to iterator()", iteratorCalled); 340 iteratorCalled = true; 341 return Collections.singleton(element).iterator(); 342 } 343 }; 344 } 345} 346 347