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.junit.contrib.truth.Truth.ASSERT; 21 22import com.google.common.annotations.GwtCompatible; 23import com.google.common.annotations.GwtIncompatible; 24import com.google.common.testing.SerializableTester; 25 26import junit.framework.TestCase; 27 28import java.util.AbstractCollection; 29import java.util.Collection; 30import java.util.Collections; 31import java.util.Iterator; 32import java.util.List; 33import java.util.ListIterator; 34import java.util.RandomAccess; 35import java.util.Set; 36import java.util.SortedSet; 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 ASSERT.that(collection).hasContentsInOrder("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog"); 84 ASSERT.that(constrained).hasContentsInOrder("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog"); 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).hasContentsInOrder("foo", "bar"); 100 ASSERT.that(collection).hasContentsInOrder("foo", "bar"); 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).hasContentsInOrder("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog"); 114 ASSERT.that(constrained).hasContentsInOrder("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog"); 115 } 116 117 public void testConstrainedSetIllegal() { 118 Set<String> set = Sets.newLinkedHashSet(asList("foo", "bar")); 119 Set<String> constrained = Constraints.constrainedSet(set, TEST_CONSTRAINT); 120 try { 121 constrained.add(TEST_ELEMENT); 122 fail("TestElementException expected"); 123 } catch (TestElementException expected) {} 124 try { 125 constrained.addAll(asList("baz", TEST_ELEMENT)); 126 fail("TestElementException expected"); 127 } catch (TestElementException expected) {} 128 ASSERT.that(constrained).hasContentsInOrder("foo", "bar"); 129 ASSERT.that(set).hasContentsInOrder("foo", "bar"); 130 } 131 132 public void testConstrainedSortedSetLegal() { 133 SortedSet<String> sortedSet = Sets.newTreeSet(asList("foo", "bar")); 134 SortedSet<String> constrained = Constraints.constrainedSortedSet( 135 sortedSet, TEST_CONSTRAINT); 136 sortedSet.add(TEST_ELEMENT); 137 constrained.add("qux"); 138 constrained.addAll(asList("cat", "dog")); 139 assertTrue(sortedSet.equals(constrained)); 140 assertTrue(constrained.equals(sortedSet)); 141 assertEquals(sortedSet.toString(), constrained.toString()); 142 assertEquals(sortedSet.hashCode(), constrained.hashCode()); 143 ASSERT.that(sortedSet).hasContentsInOrder("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT); 144 ASSERT.that(constrained).hasContentsInOrder("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT); 145 assertNull(constrained.comparator()); 146 assertEquals("bar", constrained.first()); 147 assertEquals(TEST_ELEMENT, constrained.last()); 148 } 149 150 public void testConstrainedSortedSetIllegal() { 151 SortedSet<String> sortedSet = Sets.newTreeSet(asList("foo", "bar")); 152 SortedSet<String> constrained = Constraints.constrainedSortedSet( 153 sortedSet, TEST_CONSTRAINT); 154 try { 155 constrained.add(TEST_ELEMENT); 156 fail("TestElementException expected"); 157 } catch (TestElementException expected) {} 158 try { 159 constrained.subSet("bar", "foo").add(TEST_ELEMENT); 160 fail("TestElementException expected"); 161 } catch (TestElementException expected) {} 162 try { 163 constrained.headSet("bar").add(TEST_ELEMENT); 164 fail("TestElementException expected"); 165 } catch (TestElementException expected) {} 166 try { 167 constrained.tailSet("foo").add(TEST_ELEMENT); 168 fail("TestElementException expected"); 169 } catch (TestElementException expected) {} 170 try { 171 constrained.addAll(asList("baz", TEST_ELEMENT)); 172 fail("TestElementException expected"); 173 } catch (TestElementException expected) {} 174 ASSERT.that(constrained).hasContentsInOrder("bar", "foo"); 175 ASSERT.that(sortedSet).hasContentsInOrder("bar", "foo"); 176 } 177 178 public void testConstrainedListLegal() { 179 List<String> list = Lists.newArrayList("foo", "bar"); 180 List<String> constrained = Constraints.constrainedList( 181 list, TEST_CONSTRAINT); 182 list.add(TEST_ELEMENT); 183 constrained.add("qux"); 184 constrained.addAll(asList("cat", "dog")); 185 constrained.add(1, "cow"); 186 constrained.addAll(4, asList("box", "fan")); 187 constrained.set(2, "baz"); 188 assertTrue(list.equals(constrained)); 189 assertTrue(constrained.equals(list)); 190 assertEquals(list.toString(), constrained.toString()); 191 assertEquals(list.hashCode(), constrained.hashCode()); 192 ASSERT.that(list).hasContentsInOrder( 193 "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog"); 194 ASSERT.that(constrained).hasContentsInOrder( 195 "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog"); 196 ListIterator<String> iterator = constrained.listIterator(); 197 iterator.next(); 198 iterator.set("sun"); 199 constrained.listIterator(2).add("sky"); 200 ASSERT.that(list).hasContentsInOrder( 201 "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog"); 202 ASSERT.that(constrained).hasContentsInOrder( 203 "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog"); 204 assertTrue(constrained instanceof RandomAccess); 205 } 206 207 public void testConstrainedListRandomAccessFalse() { 208 List<String> list = Lists.newLinkedList(asList("foo", "bar")); 209 List<String> constrained = Constraints.constrainedList( 210 list, TEST_CONSTRAINT); 211 list.add(TEST_ELEMENT); 212 constrained.add("qux"); 213 assertFalse(constrained instanceof RandomAccess); 214 } 215 216 public void testConstrainedListIllegal() { 217 List<String> list = Lists.newArrayList("foo", "bar"); 218 List<String> constrained = Constraints.constrainedList( 219 list, TEST_CONSTRAINT); 220 try { 221 constrained.add(TEST_ELEMENT); 222 fail("TestElementException expected"); 223 } catch (TestElementException expected) {} 224 try { 225 constrained.listIterator().add(TEST_ELEMENT); 226 fail("TestElementException expected"); 227 } catch (TestElementException expected) {} 228 try { 229 constrained.listIterator(1).add(TEST_ELEMENT); 230 fail("TestElementException expected"); 231 } catch (TestElementException expected) {} 232 try { 233 constrained.listIterator().set(TEST_ELEMENT); 234 fail("TestElementException expected"); 235 } catch (TestElementException expected) {} 236 try { 237 constrained.listIterator(1).set(TEST_ELEMENT); 238 fail("TestElementException expected"); 239 } catch (TestElementException expected) {} 240 try { 241 constrained.subList(0, 1).add(TEST_ELEMENT); 242 fail("TestElementException expected"); 243 } catch (TestElementException expected) {} 244 try { 245 constrained.add(1, TEST_ELEMENT); 246 fail("TestElementException expected"); 247 } catch (TestElementException expected) {} 248 try { 249 constrained.set(1, TEST_ELEMENT); 250 fail("TestElementException expected"); 251 } catch (TestElementException expected) {} 252 try { 253 constrained.addAll(asList("baz", TEST_ELEMENT)); 254 fail("TestElementException expected"); 255 } catch (TestElementException expected) {} 256 try { 257 constrained.addAll(1, asList("baz", TEST_ELEMENT)); 258 fail("TestElementException expected"); 259 } catch (TestElementException expected) {} 260 ASSERT.that(constrained).hasContentsInOrder("foo", "bar"); 261 ASSERT.that(list).hasContentsInOrder("foo", "bar"); 262 } 263 264 public void testConstrainedMultisetLegal() { 265 Multiset<String> multiset = HashMultiset.create(asList("foo", "bar")); 266 Multiset<String> constrained = Constraints.constrainedMultiset( 267 multiset, TEST_CONSTRAINT); 268 multiset.add(TEST_ELEMENT); 269 constrained.add("qux"); 270 constrained.addAll(asList("cat", "dog")); 271 constrained.add("cow", 2); 272 assertTrue(multiset.equals(constrained)); 273 assertTrue(constrained.equals(multiset)); 274 assertEquals(multiset.toString(), constrained.toString()); 275 assertEquals(multiset.hashCode(), constrained.hashCode()); 276 ASSERT.that(multiset).hasContentsAnyOrder( 277 "foo", "bar", TEST_ELEMENT, "qux", "cat", "dog", "cow", "cow"); 278 ASSERT.that(constrained).hasContentsAnyOrder( 279 "foo", "bar", TEST_ELEMENT, "qux", "cat", "dog", "cow", "cow"); 280 assertEquals(1, constrained.count("foo")); 281 assertEquals(1, constrained.remove("foo", 3)); 282 assertEquals(2, constrained.setCount("cow", 0)); 283 ASSERT.that(multiset).hasContentsAnyOrder("bar", TEST_ELEMENT, "qux", "cat", "dog"); 284 ASSERT.that(constrained).hasContentsAnyOrder("bar", TEST_ELEMENT, "qux", "cat", "dog"); 285 } 286 287 public void testConstrainedMultisetIllegal() { 288 Multiset<String> multiset = HashMultiset.create(asList("foo", "bar")); 289 Multiset<String> constrained = Constraints.constrainedMultiset( 290 multiset, TEST_CONSTRAINT); 291 try { 292 constrained.add(TEST_ELEMENT); 293 fail("TestElementException expected"); 294 } catch (TestElementException expected) {} 295 try { 296 constrained.add(TEST_ELEMENT, 2); 297 fail("TestElementException expected"); 298 } catch (TestElementException expected) {} 299 try { 300 constrained.addAll(asList("baz", TEST_ELEMENT)); 301 fail("TestElementException expected"); 302 } catch (TestElementException expected) {} 303 ASSERT.that(constrained).hasContentsAnyOrder("foo", "bar"); 304 ASSERT.that(multiset).hasContentsAnyOrder("foo", "bar"); 305 } 306 307 public void testNefariousAddAll() { 308 List<String> list = Lists.newArrayList("foo", "bar"); 309 List<String> constrained = Constraints.constrainedList( 310 list, TEST_CONSTRAINT); 311 Collection<String> onceIterable = onceIterableCollection("baz"); 312 constrained.addAll(onceIterable); 313 ASSERT.that(constrained).hasContentsInOrder("foo", "bar", "baz"); 314 ASSERT.that(list).hasContentsInOrder("foo", "bar", "baz"); 315 } 316 317 /** 318 * Returns a "nefarious" collection, which permits only one call to 319 * iterator(). This verifies that the constrained collection uses a defensive 320 * copy instead of potentially checking the elements in one snapshot and 321 * adding the elements from another. 322 * 323 * @param element the element to be contained in the collection 324 */ 325 static <E> Collection<E> onceIterableCollection(final E element) { 326 return new AbstractCollection<E>() { 327 boolean iteratorCalled; 328 @Override public int size() { 329 /* 330 * We could make the collection empty, but that seems more likely to 331 * trigger special cases (so maybe we should test both empty and 332 * nonempty...). 333 */ 334 return 1; 335 } 336 @Override public Iterator<E> iterator() { 337 assertFalse("Expected only one call to iterator()", iteratorCalled); 338 iteratorCalled = true; 339 return Collections.singleton(element).iterator(); 340 } 341 }; 342 } 343 344 @GwtIncompatible("SerializableTester") 345 public void testSerialization() { 346 // TODO: Test serialization of constrained collections. 347 assertSame(Constraints.notNull(), 348 SerializableTester.reserialize(Constraints.notNull())); 349 } 350} 351