Home | History | Annotate | Download | only in collect
      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 java.util.Arrays.asList;
     20 import static org.junit.contrib.truth.Truth.ASSERT;
     21 
     22 import com.google.common.annotations.GwtCompatible;
     23 import com.google.common.annotations.GwtIncompatible;
     24 import com.google.common.testing.SerializableTester;
     25 
     26 import junit.framework.TestCase;
     27 
     28 import java.util.AbstractCollection;
     29 import java.util.Collection;
     30 import java.util.Collections;
     31 import java.util.Iterator;
     32 import java.util.List;
     33 import java.util.ListIterator;
     34 import java.util.RandomAccess;
     35 import java.util.Set;
     36 import java.util.SortedSet;
     37 
     38 /**
     39  * Tests for {@code Constraints}.
     40  *
     41  * @author Mike Bostock
     42  * @author Jared Levy
     43  */
     44 @GwtCompatible(emulated = true)
     45 public 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