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"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the License
     10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     11  * or implied. See the License for the specific language governing permissions and limitations under
     12  * the License.
     13  */
     14 
     15 package com.google.common.collect;
     16 
     17 import static com.google.common.base.Preconditions.checkArgument;
     18 
     19 import com.google.common.annotations.GwtCompatible;
     20 import com.google.common.annotations.GwtIncompatible;
     21 import com.google.common.collect.testing.features.CollectionFeature;
     22 import com.google.common.collect.testing.features.CollectionSize;
     23 import com.google.common.collect.testing.google.MultisetTestSuiteBuilder;
     24 import com.google.common.collect.testing.google.TestStringMultisetGenerator;
     25 
     26 import junit.framework.Test;
     27 import junit.framework.TestCase;
     28 import junit.framework.TestSuite;
     29 
     30 import java.io.Serializable;
     31 import java.util.Collections;
     32 import java.util.Iterator;
     33 import java.util.Map;
     34 import java.util.concurrent.atomic.AtomicInteger;
     35 
     36 import javax.annotation.Nullable;
     37 
     38 /**
     39  * Unit test for {@link AbstractMultiset}.
     40  *
     41  * @author Kevin Bourrillion
     42  * @author Louis Wasserman
     43  */
     44 @SuppressWarnings("serial") // No serialization is used in this test
     45 @GwtCompatible(emulated = true)
     46 public class SimpleAbstractMultisetTest extends TestCase {
     47   @GwtIncompatible("suite")
     48   public static Test suite() {
     49     TestSuite suite = new TestSuite();
     50     suite.addTestSuite(SimpleAbstractMultisetTest.class);
     51     suite.addTest(MultisetTestSuiteBuilder.using(new TestStringMultisetGenerator() {
     52           @Override
     53           protected Multiset<String> create(String[] elements) {
     54             Multiset<String> ms = new NoRemoveMultiset<String>();
     55             Collections.addAll(ms, elements);
     56             return ms;
     57           }
     58         })
     59         .named("NoRemoveMultiset")
     60         .withFeatures(CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_VALUES,
     61             CollectionFeature.SUPPORTS_ADD)
     62         .createTestSuite());
     63     return suite;
     64   }
     65 
     66   public void testFastAddAllMultiset() {
     67     final AtomicInteger addCalls = new AtomicInteger();
     68     Multiset<String> multiset = new NoRemoveMultiset<String>() {
     69       @Override
     70       public int add(String element, int occurrences) {
     71         addCalls.incrementAndGet();
     72         return super.add(element, occurrences);
     73       }
     74     };
     75     ImmutableMultiset<String> adds =
     76         new ImmutableMultiset.Builder<String>().addCopies("x", 10).build();
     77     multiset.addAll(adds);
     78     assertEquals(addCalls.get(), 1);
     79   }
     80 
     81   public void testRemoveUnsupported() {
     82     Multiset<String> multiset = new NoRemoveMultiset<String>();
     83     multiset.add("a");
     84     try {
     85       multiset.remove("a");
     86       fail();
     87     } catch (UnsupportedOperationException expected) {}
     88     assertTrue(multiset.contains("a"));
     89   }
     90 
     91   private static class NoRemoveMultiset<E> extends AbstractMultiset<E>
     92       implements Serializable {
     93     final Map<E, Integer> backingMap = Maps.newHashMap();
     94 
     95     @Override public int add(@Nullable E element, int occurrences) {
     96       checkArgument(occurrences >= 0);
     97       Integer frequency = backingMap.get(element);
     98       if (frequency == null) {
     99         frequency = 0;
    100       }
    101       if (occurrences == 0) {
    102         return frequency;
    103       }
    104       checkArgument(occurrences <= Integer.MAX_VALUE - frequency);
    105       backingMap.put(element, frequency + occurrences);
    106       return frequency;
    107     }
    108 
    109     @Override
    110     Iterator<Entry<E>> entryIterator() {
    111       final Iterator<Map.Entry<E, Integer>> backingEntries = backingMap.entrySet().iterator();
    112       return new UnmodifiableIterator<Multiset.Entry<E>>() {
    113         @Override
    114         public boolean hasNext() {
    115           return backingEntries.hasNext();
    116         }
    117 
    118         @Override
    119         public Multiset.Entry<E> next() {
    120           final Map.Entry<E, Integer> mapEntry = backingEntries.next();
    121           return new Multisets.AbstractEntry<E>() {
    122             @Override
    123             public E getElement() {
    124               return mapEntry.getKey();
    125             }
    126 
    127             @Override
    128             public int getCount() {
    129               Integer frequency = backingMap.get(getElement());
    130               return (frequency == null) ? 0 : frequency;
    131             }
    132           };
    133         }
    134       };
    135     }
    136 
    137     @Override
    138     int distinctElements() {
    139       return backingMap.size();
    140     }
    141   }
    142 }
    143