001/* 002 * Copyright (C) 2008 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect.testing.google; 018 019import static com.google.common.base.Preconditions.checkArgument; 020 021import com.google.common.annotations.GwtIncompatible; 022import com.google.common.collect.Multiset; 023import com.google.common.collect.Multiset.Entry; 024import com.google.common.collect.Multisets; 025import com.google.common.collect.testing.AbstractCollectionTestSuiteBuilder; 026import com.google.common.collect.testing.AbstractTester; 027import com.google.common.collect.testing.FeatureSpecificTestSuiteBuilder; 028import com.google.common.collect.testing.Helpers; 029import com.google.common.collect.testing.OneSizeTestContainerGenerator; 030import com.google.common.collect.testing.SampleElements; 031import com.google.common.collect.testing.SetTestSuiteBuilder; 032import com.google.common.collect.testing.TestSetGenerator; 033import com.google.common.collect.testing.features.CollectionFeature; 034import com.google.common.collect.testing.features.Feature; 035import com.google.common.collect.testing.testers.CollectionSerializationEqualTester; 036import com.google.common.testing.SerializableTester; 037import java.util.ArrayList; 038import java.util.Collection; 039import java.util.Collections; 040import java.util.HashSet; 041import java.util.LinkedHashMap; 042import java.util.LinkedHashSet; 043import java.util.List; 044import java.util.Map; 045import java.util.Set; 046import junit.framework.TestSuite; 047 048/** 049 * Creates, based on your criteria, a JUnit test suite that exhaustively tests a {@code Multiset} 050 * implementation. 051 * 052 * @author Jared Levy 053 * @author Louis Wasserman 054 */ 055@GwtIncompatible 056public class MultisetTestSuiteBuilder<E> 057 extends AbstractCollectionTestSuiteBuilder<MultisetTestSuiteBuilder<E>, E> { 058 public static <E> MultisetTestSuiteBuilder<E> using(TestMultisetGenerator<E> generator) { 059 return new MultisetTestSuiteBuilder<E>().usingGenerator(generator); 060 } 061 062 public enum NoRecurse implements Feature<Void> { 063 NO_ENTRY_SET; 064 065 @Override 066 public Set<Feature<? super Void>> getImpliedFeatures() { 067 return Collections.emptySet(); 068 } 069 } 070 071 @SuppressWarnings("rawtypes") // class literals 072 @Override 073 protected List<Class<? extends AbstractTester>> getTesters() { 074 List<Class<? extends AbstractTester>> testers = Helpers.copyToList(super.getTesters()); 075 testers.add(CollectionSerializationEqualTester.class); 076 testers.add(MultisetAddTester.class); 077 testers.add(MultisetContainsTester.class); 078 testers.add(MultisetCountTester.class); 079 testers.add(MultisetElementSetTester.class); 080 testers.add(MultisetEqualsTester.class); 081 testers.add(MultisetForEachEntryTester.class); 082 testers.add(MultisetReadsTester.class); 083 testers.add(MultisetSetCountConditionallyTester.class); 084 testers.add(MultisetSetCountUnconditionallyTester.class); 085 testers.add(MultisetRemoveTester.class); 086 testers.add(MultisetEntrySetTester.class); 087 testers.add(MultisetIteratorTester.class); 088 testers.add(MultisetSerializationTester.class); 089 return testers; 090 } 091 092 private static Set<Feature<?>> computeEntrySetFeatures(Set<Feature<?>> features) { 093 Set<Feature<?>> derivedFeatures = new HashSet<>(features); 094 derivedFeatures.remove(CollectionFeature.GENERAL_PURPOSE); 095 derivedFeatures.remove(CollectionFeature.SUPPORTS_ADD); 096 derivedFeatures.remove(CollectionFeature.ALLOWS_NULL_VALUES); 097 derivedFeatures.add(CollectionFeature.REJECTS_DUPLICATES_AT_CREATION); 098 if (!derivedFeatures.remove(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS)) { 099 derivedFeatures.remove(CollectionFeature.SERIALIZABLE); 100 } 101 return derivedFeatures; 102 } 103 104 static Set<Feature<?>> computeElementSetFeatures(Set<Feature<?>> features) { 105 Set<Feature<?>> derivedFeatures = new HashSet<>(features); 106 derivedFeatures.remove(CollectionFeature.GENERAL_PURPOSE); 107 derivedFeatures.remove(CollectionFeature.SUPPORTS_ADD); 108 if (!derivedFeatures.remove(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS)) { 109 derivedFeatures.remove(CollectionFeature.SERIALIZABLE); 110 } 111 return derivedFeatures; 112 } 113 114 private static Set<Feature<?>> computeReserializedMultisetFeatures(Set<Feature<?>> features) { 115 Set<Feature<?>> derivedFeatures = new HashSet<>(features); 116 derivedFeatures.remove(CollectionFeature.SERIALIZABLE); 117 derivedFeatures.remove(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS); 118 return derivedFeatures; 119 } 120 121 @Override 122 protected List<TestSuite> createDerivedSuites( 123 FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<Collection<E>, E>> 124 parentBuilder) { 125 List<TestSuite> derivedSuites = new ArrayList<>(super.createDerivedSuites(parentBuilder)); 126 127 derivedSuites.add(createElementSetTestSuite(parentBuilder)); 128 129 if (!parentBuilder.getFeatures().contains(NoRecurse.NO_ENTRY_SET)) { 130 derivedSuites.add( 131 SetTestSuiteBuilder.using(new EntrySetGenerator<E>(parentBuilder.getSubjectGenerator())) 132 .named(getName() + ".entrySet") 133 .withFeatures(computeEntrySetFeatures(parentBuilder.getFeatures())) 134 .suppressing(parentBuilder.getSuppressedTests()) 135 .withSetUp(parentBuilder.getSetUp()) 136 .withTearDown(parentBuilder.getTearDown()) 137 .createTestSuite()); 138 } 139 140 if (parentBuilder.getFeatures().contains(CollectionFeature.SERIALIZABLE)) { 141 derivedSuites.add( 142 MultisetTestSuiteBuilder.using( 143 new ReserializedMultisetGenerator<E>(parentBuilder.getSubjectGenerator())) 144 .named(getName() + " reserialized") 145 .withFeatures(computeReserializedMultisetFeatures(parentBuilder.getFeatures())) 146 .suppressing(parentBuilder.getSuppressedTests()) 147 .withSetUp(parentBuilder.getSetUp()) 148 .withTearDown(parentBuilder.getTearDown()) 149 .createTestSuite()); 150 } 151 return derivedSuites; 152 } 153 154 TestSuite createElementSetTestSuite( 155 FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<Collection<E>, E>> 156 parentBuilder) { 157 return SetTestSuiteBuilder.using( 158 new ElementSetGenerator<E>(parentBuilder.getSubjectGenerator())) 159 .named(getName() + ".elementSet") 160 .withFeatures(computeElementSetFeatures(parentBuilder.getFeatures())) 161 .suppressing(parentBuilder.getSuppressedTests()) 162 .withSetUp(parentBuilder.getSetUp()) 163 .withTearDown(parentBuilder.getTearDown()) 164 .createTestSuite(); 165 } 166 167 static class ElementSetGenerator<E> implements TestSetGenerator<E> { 168 final OneSizeTestContainerGenerator<Collection<E>, E> gen; 169 170 ElementSetGenerator(OneSizeTestContainerGenerator<Collection<E>, E> gen) { 171 this.gen = gen; 172 } 173 174 @Override 175 public SampleElements<E> samples() { 176 return gen.samples(); 177 } 178 179 @Override 180 public Set<E> create(Object... elements) { 181 Object[] duplicated = new Object[elements.length * 2]; 182 for (int i = 0; i < elements.length; i++) { 183 duplicated[i] = elements[i]; 184 duplicated[i + elements.length] = elements[i]; 185 } 186 return ((Multiset<E>) gen.create(duplicated)).elementSet(); 187 } 188 189 @Override 190 public E[] createArray(int length) { 191 return gen.createArray(length); 192 } 193 194 @Override 195 public Iterable<E> order(List<E> insertionOrder) { 196 return gen.order(new ArrayList<E>(new LinkedHashSet<E>(insertionOrder))); 197 } 198 } 199 200 static class EntrySetGenerator<E> implements TestSetGenerator<Multiset.Entry<E>> { 201 final OneSizeTestContainerGenerator<Collection<E>, E> gen; 202 203 private EntrySetGenerator(OneSizeTestContainerGenerator<Collection<E>, E> gen) { 204 this.gen = gen; 205 } 206 207 @Override 208 public SampleElements<Multiset.Entry<E>> samples() { 209 SampleElements<E> samples = gen.samples(); 210 return new SampleElements<>( 211 Multisets.immutableEntry(samples.e0(), 3), 212 Multisets.immutableEntry(samples.e1(), 4), 213 Multisets.immutableEntry(samples.e2(), 1), 214 Multisets.immutableEntry(samples.e3(), 5), 215 Multisets.immutableEntry(samples.e4(), 2)); 216 } 217 218 @Override 219 public Set<Multiset.Entry<E>> create(Object... entries) { 220 List<Object> contents = new ArrayList<>(); 221 Set<E> elements = new HashSet<>(); 222 for (Object o : entries) { 223 @SuppressWarnings("unchecked") 224 Multiset.Entry<E> entry = (Entry<E>) o; 225 checkArgument( 226 elements.add(entry.getElement()), "Duplicate keys not allowed in EntrySetGenerator"); 227 for (int i = 0; i < entry.getCount(); i++) { 228 contents.add(entry.getElement()); 229 } 230 } 231 return ((Multiset<E>) gen.create(contents.toArray())).entrySet(); 232 } 233 234 @SuppressWarnings("unchecked") 235 @Override 236 public Multiset.Entry<E>[] createArray(int length) { 237 return (Multiset.Entry<E>[]) new Multiset.Entry<?>[length]; 238 } 239 240 @Override 241 public Iterable<Entry<E>> order(List<Entry<E>> insertionOrder) { 242 // We mimic the order from gen. 243 Map<E, Entry<E>> map = new LinkedHashMap<>(); 244 for (Entry<E> entry : insertionOrder) { 245 map.put(entry.getElement(), entry); 246 } 247 248 Set<E> seen = new HashSet<>(); 249 List<Entry<E>> order = new ArrayList<>(); 250 for (E e : gen.order(new ArrayList<E>(map.keySet()))) { 251 if (seen.add(e)) { 252 order.add(map.get(e)); 253 } 254 } 255 return order; 256 } 257 } 258 259 static class ReserializedMultisetGenerator<E> implements TestMultisetGenerator<E> { 260 final OneSizeTestContainerGenerator<Collection<E>, E> gen; 261 262 private ReserializedMultisetGenerator(OneSizeTestContainerGenerator<Collection<E>, E> gen) { 263 this.gen = gen; 264 } 265 266 @Override 267 public SampleElements<E> samples() { 268 return gen.samples(); 269 } 270 271 @Override 272 public Multiset<E> create(Object... elements) { 273 return (Multiset<E>) SerializableTester.reserialize(gen.create(elements)); 274 } 275 276 @Override 277 public E[] createArray(int length) { 278 return gen.createArray(length); 279 } 280 281 @Override 282 public Iterable<E> order(List<E> insertionOrder) { 283 return gen.order(insertionOrder); 284 } 285 } 286}