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 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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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    */
    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