1 /* 2 * Copyright (C) 2012 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.testing.google; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.collect.testing.Helpers.mapEntry; 21 22 import com.google.common.annotations.GwtIncompatible; 23 import com.google.common.collect.ImmutableList; 24 import com.google.common.collect.ImmutableMultimap; 25 import com.google.common.collect.Multimap; 26 import com.google.common.collect.Multiset; 27 import com.google.common.collect.testing.AbstractTester; 28 import com.google.common.collect.testing.CollectionTestSuiteBuilder; 29 import com.google.common.collect.testing.DerivedGenerator; 30 import com.google.common.collect.testing.FeatureSpecificTestSuiteBuilder; 31 import com.google.common.collect.testing.Helpers; 32 import com.google.common.collect.testing.MapTestSuiteBuilder; 33 import com.google.common.collect.testing.OneSizeTestContainerGenerator; 34 import com.google.common.collect.testing.PerCollectionSizeTestSuiteBuilder; 35 import com.google.common.collect.testing.SampleElements; 36 import com.google.common.collect.testing.TestCollectionGenerator; 37 import com.google.common.collect.testing.TestMapGenerator; 38 import com.google.common.collect.testing.TestSubjectGenerator; 39 import com.google.common.collect.testing.features.CollectionFeature; 40 import com.google.common.collect.testing.features.CollectionSize; 41 import com.google.common.collect.testing.features.Feature; 42 import com.google.common.collect.testing.features.ListFeature; 43 import com.google.common.collect.testing.features.MapFeature; 44 import com.google.common.testing.SerializableTester; 45 import java.util.ArrayList; 46 import java.util.Collection; 47 import java.util.Collections; 48 import java.util.EnumSet; 49 import java.util.HashMap; 50 import java.util.HashSet; 51 import java.util.Iterator; 52 import java.util.LinkedHashMap; 53 import java.util.List; 54 import java.util.Map; 55 import java.util.Map.Entry; 56 import java.util.Set; 57 import junit.framework.TestSuite; 58 59 /** 60 * Creates, based on your criteria, a JUnit test suite that exhaustively tests a {@code Multimap} 61 * implementation. 62 * 63 * @author Louis Wasserman 64 */ 65 @GwtIncompatible 66 public class MultimapTestSuiteBuilder<K, V, M extends Multimap<K, V>> 67 extends PerCollectionSizeTestSuiteBuilder< 68 MultimapTestSuiteBuilder<K, V, M>, TestMultimapGenerator<K, V, M>, M, Entry<K, V>> { 69 using( TestMultimapGenerator<K, V, M> generator)70 public static <K, V, M extends Multimap<K, V>> MultimapTestSuiteBuilder<K, V, M> using( 71 TestMultimapGenerator<K, V, M> generator) { 72 return new MultimapTestSuiteBuilder<K, V, M>().usingGenerator(generator); 73 } 74 75 // Class parameters must be raw. 76 @Override getTesters()77 protected List<Class<? extends AbstractTester>> getTesters() { 78 return ImmutableList.<Class<? extends AbstractTester>>of( 79 MultimapAsMapGetTester.class, 80 MultimapAsMapTester.class, 81 MultimapSizeTester.class, 82 MultimapClearTester.class, 83 MultimapContainsKeyTester.class, 84 MultimapContainsValueTester.class, 85 MultimapContainsEntryTester.class, 86 MultimapEntriesTester.class, 87 MultimapEqualsTester.class, 88 MultimapForEachTester.class, 89 MultimapGetTester.class, 90 MultimapKeySetTester.class, 91 MultimapKeysTester.class, 92 MultimapPutTester.class, 93 MultimapPutAllMultimapTester.class, 94 MultimapPutIterableTester.class, 95 MultimapReplaceValuesTester.class, 96 MultimapRemoveEntryTester.class, 97 MultimapRemoveAllTester.class, 98 MultimapToStringTester.class, 99 MultimapValuesTester.class); 100 } 101 102 @Override createDerivedSuites( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)103 protected List<TestSuite> createDerivedSuites( 104 FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> 105 parentBuilder) { 106 // TODO: Once invariant support is added, supply invariants to each of the 107 // derived suites, to check that mutations to the derived collections are 108 // reflected in the underlying map. 109 110 List<TestSuite> derivedSuites = super.createDerivedSuites(parentBuilder); 111 112 if (parentBuilder.getFeatures().contains(CollectionFeature.SERIALIZABLE)) { 113 derivedSuites.add( 114 MultimapTestSuiteBuilder.using( 115 new ReserializedMultimapGenerator<K, V, M>(parentBuilder.getSubjectGenerator())) 116 .withFeatures(computeReserializedMultimapFeatures(parentBuilder.getFeatures())) 117 .named(parentBuilder.getName() + " reserialized") 118 .suppressing(parentBuilder.getSuppressedTests()) 119 .withSetUp(parentBuilder.getSetUp()) 120 .withTearDown(parentBuilder.getTearDown()) 121 .createTestSuite()); 122 } 123 124 derivedSuites.add( 125 MapTestSuiteBuilder.using(new AsMapGenerator<K, V, M>(parentBuilder.getSubjectGenerator())) 126 .withFeatures(computeAsMapFeatures(parentBuilder.getFeatures())) 127 .named(parentBuilder.getName() + ".asMap") 128 .suppressing(parentBuilder.getSuppressedTests()) 129 .withSetUp(parentBuilder.getSetUp()) 130 .withTearDown(parentBuilder.getTearDown()) 131 .createTestSuite()); 132 133 derivedSuites.add(computeEntriesTestSuite(parentBuilder)); 134 derivedSuites.add(computeMultimapGetTestSuite(parentBuilder)); 135 derivedSuites.add(computeMultimapAsMapGetTestSuite(parentBuilder)); 136 derivedSuites.add(computeKeysTestSuite(parentBuilder)); 137 derivedSuites.add(computeValuesTestSuite(parentBuilder)); 138 139 return derivedSuites; 140 } 141 computeValuesTestSuite( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)142 TestSuite computeValuesTestSuite( 143 FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> 144 parentBuilder) { 145 return CollectionTestSuiteBuilder.using( 146 new ValuesGenerator<K, V, M>(parentBuilder.getSubjectGenerator())) 147 .withFeatures(computeValuesFeatures(parentBuilder.getFeatures())) 148 .named(parentBuilder.getName() + ".values") 149 .suppressing(parentBuilder.getSuppressedTests()) 150 .createTestSuite(); 151 } 152 computeEntriesTestSuite( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)153 TestSuite computeEntriesTestSuite( 154 FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> 155 parentBuilder) { 156 return CollectionTestSuiteBuilder.using( 157 new EntriesGenerator<K, V, M>(parentBuilder.getSubjectGenerator())) 158 .withFeatures(computeEntriesFeatures(parentBuilder.getFeatures())) 159 .named(parentBuilder.getName() + ".entries") 160 .suppressing(parentBuilder.getSuppressedTests()) 161 .withSetUp(parentBuilder.getSetUp()) 162 .withTearDown(parentBuilder.getTearDown()) 163 .createTestSuite(); 164 } 165 computeMultimapGetTestSuite( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)166 TestSuite computeMultimapGetTestSuite( 167 FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> 168 parentBuilder) { 169 return CollectionTestSuiteBuilder.using( 170 new MultimapGetGenerator<K, V, M>(parentBuilder.getSubjectGenerator())) 171 .withFeatures(computeMultimapGetFeatures(parentBuilder.getFeatures())) 172 .named(parentBuilder.getName() + ".get[key]") 173 .suppressing(parentBuilder.getSuppressedTests()) 174 .withSetUp(parentBuilder.getSetUp()) 175 .withTearDown(parentBuilder.getTearDown()) 176 .createTestSuite(); 177 } 178 computeMultimapAsMapGetTestSuite( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)179 TestSuite computeMultimapAsMapGetTestSuite( 180 FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> 181 parentBuilder) { 182 Set<Feature<?>> features = computeMultimapAsMapGetFeatures(parentBuilder.getFeatures()); 183 if (Collections.disjoint(features, EnumSet.allOf(CollectionSize.class))) { 184 return new TestSuite(); 185 } else { 186 return CollectionTestSuiteBuilder.using( 187 new MultimapAsMapGetGenerator<K, V, M>(parentBuilder.getSubjectGenerator())) 188 .withFeatures(features) 189 .named(parentBuilder.getName() + ".asMap[].get[key]") 190 .suppressing(parentBuilder.getSuppressedTests()) 191 .withSetUp(parentBuilder.getSetUp()) 192 .withTearDown(parentBuilder.getTearDown()) 193 .createTestSuite(); 194 } 195 } 196 computeKeysTestSuite( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)197 TestSuite computeKeysTestSuite( 198 FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> 199 parentBuilder) { 200 return MultisetTestSuiteBuilder.using( 201 new KeysGenerator<K, V, M>(parentBuilder.getSubjectGenerator())) 202 .withFeatures(computeKeysFeatures(parentBuilder.getFeatures())) 203 .named(parentBuilder.getName() + ".keys") 204 .suppressing(parentBuilder.getSuppressedTests()) 205 .withSetUp(parentBuilder.getSetUp()) 206 .withTearDown(parentBuilder.getTearDown()) 207 .createTestSuite(); 208 } 209 computeDerivedCollectionFeatures(Set<Feature<?>> multimapFeatures)210 static Set<Feature<?>> computeDerivedCollectionFeatures(Set<Feature<?>> multimapFeatures) { 211 Set<Feature<?>> derivedFeatures = Helpers.copyToSet(multimapFeatures); 212 if (!derivedFeatures.remove(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS)) { 213 derivedFeatures.remove(CollectionFeature.SERIALIZABLE); 214 } 215 if (derivedFeatures.remove(MapFeature.SUPPORTS_REMOVE)) { 216 derivedFeatures.add(CollectionFeature.SUPPORTS_REMOVE); 217 } 218 return derivedFeatures; 219 } 220 computeEntriesFeatures(Set<Feature<?>> multimapFeatures)221 static Set<Feature<?>> computeEntriesFeatures(Set<Feature<?>> multimapFeatures) { 222 Set<Feature<?>> result = computeDerivedCollectionFeatures(multimapFeatures); 223 if (multimapFeatures.contains(MapFeature.ALLOWS_NULL_ENTRY_QUERIES)) { 224 result.add(CollectionFeature.ALLOWS_NULL_QUERIES); 225 } 226 return result; 227 } 228 computeValuesFeatures(Set<Feature<?>> multimapFeatures)229 static Set<Feature<?>> computeValuesFeatures(Set<Feature<?>> multimapFeatures) { 230 Set<Feature<?>> result = computeDerivedCollectionFeatures(multimapFeatures); 231 if (multimapFeatures.contains(MapFeature.ALLOWS_NULL_VALUES)) { 232 result.add(CollectionFeature.ALLOWS_NULL_VALUES); 233 } 234 if (multimapFeatures.contains(MapFeature.ALLOWS_NULL_VALUE_QUERIES)) { 235 result.add(CollectionFeature.ALLOWS_NULL_QUERIES); 236 } 237 return result; 238 } 239 computeKeysFeatures(Set<Feature<?>> multimapFeatures)240 static Set<Feature<?>> computeKeysFeatures(Set<Feature<?>> multimapFeatures) { 241 Set<Feature<?>> result = computeDerivedCollectionFeatures(multimapFeatures); 242 if (multimapFeatures.contains(MapFeature.ALLOWS_NULL_KEYS)) { 243 result.add(CollectionFeature.ALLOWS_NULL_VALUES); 244 } 245 if (multimapFeatures.contains(MapFeature.ALLOWS_NULL_KEY_QUERIES)) { 246 result.add(CollectionFeature.ALLOWS_NULL_QUERIES); 247 } 248 return result; 249 } 250 computeReserializedMultimapFeatures( Set<Feature<?>> multimapFeatures)251 private static Set<Feature<?>> computeReserializedMultimapFeatures( 252 Set<Feature<?>> multimapFeatures) { 253 Set<Feature<?>> derivedFeatures = Helpers.copyToSet(multimapFeatures); 254 derivedFeatures.remove(CollectionFeature.SERIALIZABLE); 255 derivedFeatures.remove(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS); 256 return derivedFeatures; 257 } 258 computeAsMapFeatures(Set<Feature<?>> multimapFeatures)259 private static Set<Feature<?>> computeAsMapFeatures(Set<Feature<?>> multimapFeatures) { 260 Set<Feature<?>> derivedFeatures = Helpers.copyToSet(multimapFeatures); 261 derivedFeatures.remove(MapFeature.GENERAL_PURPOSE); 262 derivedFeatures.remove(MapFeature.SUPPORTS_PUT); 263 derivedFeatures.remove(MapFeature.ALLOWS_NULL_VALUES); 264 derivedFeatures.add(MapFeature.ALLOWS_NULL_VALUE_QUERIES); 265 derivedFeatures.add(MapFeature.REJECTS_DUPLICATES_AT_CREATION); 266 if (!derivedFeatures.contains(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS)) { 267 derivedFeatures.remove(CollectionFeature.SERIALIZABLE); 268 } 269 return derivedFeatures; 270 } 271 272 private static final ImmutableMultimap<Feature<?>, Feature<?>> GET_FEATURE_MAP = 273 ImmutableMultimap.<Feature<?>, Feature<?>>builder() 274 .put( 275 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 276 CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION) 277 .put(MapFeature.GENERAL_PURPOSE, ListFeature.SUPPORTS_ADD_WITH_INDEX) 278 .put(MapFeature.GENERAL_PURPOSE, ListFeature.SUPPORTS_REMOVE_WITH_INDEX) 279 .put(MapFeature.GENERAL_PURPOSE, ListFeature.SUPPORTS_SET) 280 .put(MapFeature.ALLOWS_NULL_VALUE_QUERIES, CollectionFeature.ALLOWS_NULL_QUERIES) 281 .put(MapFeature.ALLOWS_NULL_VALUES, CollectionFeature.ALLOWS_NULL_VALUES) 282 .put(MapFeature.SUPPORTS_REMOVE, CollectionFeature.SUPPORTS_REMOVE) 283 .put(MapFeature.SUPPORTS_PUT, CollectionFeature.SUPPORTS_ADD) 284 .build(); 285 computeMultimapGetFeatures(Set<Feature<?>> multimapFeatures)286 Set<Feature<?>> computeMultimapGetFeatures(Set<Feature<?>> multimapFeatures) { 287 Set<Feature<?>> derivedFeatures = Helpers.copyToSet(multimapFeatures); 288 for (Entry<Feature<?>, Feature<?>> entry : GET_FEATURE_MAP.entries()) { 289 if (derivedFeatures.contains(entry.getKey())) { 290 derivedFeatures.add(entry.getValue()); 291 } 292 } 293 if (derivedFeatures.remove(MultimapFeature.VALUE_COLLECTIONS_SUPPORT_ITERATOR_REMOVE)) { 294 derivedFeatures.add(CollectionFeature.SUPPORTS_ITERATOR_REMOVE); 295 } 296 if (!derivedFeatures.contains(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS)) { 297 derivedFeatures.remove(CollectionFeature.SERIALIZABLE); 298 } 299 derivedFeatures.removeAll(GET_FEATURE_MAP.keySet()); 300 return derivedFeatures; 301 } 302 computeMultimapAsMapGetFeatures(Set<Feature<?>> multimapFeatures)303 Set<Feature<?>> computeMultimapAsMapGetFeatures(Set<Feature<?>> multimapFeatures) { 304 Set<Feature<?>> derivedFeatures = 305 Helpers.copyToSet(computeMultimapGetFeatures(multimapFeatures)); 306 if (derivedFeatures.remove(CollectionSize.ANY)) { 307 derivedFeatures.addAll(CollectionSize.ANY.getImpliedFeatures()); 308 } 309 derivedFeatures.remove(CollectionSize.ZERO); 310 return derivedFeatures; 311 } 312 313 private static class AsMapGenerator<K, V, M extends Multimap<K, V>> 314 implements TestMapGenerator<K, Collection<V>>, DerivedGenerator { 315 private final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator; 316 AsMapGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)317 public AsMapGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) { 318 this.multimapGenerator = multimapGenerator; 319 } 320 321 @Override getInnerGenerator()322 public TestSubjectGenerator<?> getInnerGenerator() { 323 return multimapGenerator; 324 } 325 createCollection(V v)326 private Collection<V> createCollection(V v) { 327 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 328 .createCollection(Collections.singleton(v)); 329 } 330 331 @Override samples()332 public SampleElements<Entry<K, Collection<V>>> samples() { 333 SampleElements<K> sampleKeys = 334 ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()).sampleKeys(); 335 SampleElements<V> sampleValues = 336 ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()).sampleValues(); 337 return new SampleElements<>( 338 mapEntry(sampleKeys.e0(), createCollection(sampleValues.e0())), 339 mapEntry(sampleKeys.e1(), createCollection(sampleValues.e1())), 340 mapEntry(sampleKeys.e2(), createCollection(sampleValues.e2())), 341 mapEntry(sampleKeys.e3(), createCollection(sampleValues.e3())), 342 mapEntry(sampleKeys.e4(), createCollection(sampleValues.e4()))); 343 } 344 345 @Override create(Object... elements)346 public Map<K, Collection<V>> create(Object... elements) { 347 Set<K> keySet = new HashSet<>(); 348 List<Entry<K, V>> builder = new ArrayList<>(); 349 for (Object o : elements) { 350 Entry<K, Collection<V>> entry = (Entry<K, Collection<V>>) o; 351 keySet.add(entry.getKey()); 352 for (V v : entry.getValue()) { 353 builder.add(mapEntry(entry.getKey(), v)); 354 } 355 } 356 checkArgument(keySet.size() == elements.length, "Duplicate keys"); 357 return multimapGenerator.create(builder.toArray()).asMap(); 358 } 359 360 @SuppressWarnings("unchecked") 361 @Override createArray(int length)362 public Entry<K, Collection<V>>[] createArray(int length) { 363 return new Entry[length]; 364 } 365 366 @Override order(List<Entry<K, Collection<V>>> insertionOrder)367 public Iterable<Entry<K, Collection<V>>> order(List<Entry<K, Collection<V>>> insertionOrder) { 368 Map<K, Collection<V>> map = new HashMap<>(); 369 List<Entry<K, V>> builder = new ArrayList<>(); 370 for (Entry<K, Collection<V>> entry : insertionOrder) { 371 for (V v : entry.getValue()) { 372 builder.add(mapEntry(entry.getKey(), v)); 373 } 374 map.put(entry.getKey(), entry.getValue()); 375 } 376 Iterable<Entry<K, V>> ordered = multimapGenerator.order(builder); 377 LinkedHashMap<K, Collection<V>> orderedMap = new LinkedHashMap<>(); 378 for (Entry<K, V> entry : ordered) { 379 orderedMap.put(entry.getKey(), map.get(entry.getKey())); 380 } 381 return orderedMap.entrySet(); 382 } 383 384 @Override createKeyArray(int length)385 public K[] createKeyArray(int length) { 386 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 387 .createKeyArray(length); 388 } 389 390 @SuppressWarnings("unchecked") 391 @Override createValueArray(int length)392 public Collection<V>[] createValueArray(int length) { 393 return new Collection[length]; 394 } 395 } 396 397 static class EntriesGenerator<K, V, M extends Multimap<K, V>> 398 implements TestCollectionGenerator<Entry<K, V>>, DerivedGenerator { 399 private final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator; 400 EntriesGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)401 public EntriesGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) { 402 this.multimapGenerator = multimapGenerator; 403 } 404 405 @Override getInnerGenerator()406 public TestSubjectGenerator<?> getInnerGenerator() { 407 return multimapGenerator; 408 } 409 410 @Override samples()411 public SampleElements<Entry<K, V>> samples() { 412 return multimapGenerator.samples(); 413 } 414 415 @Override create(Object... elements)416 public Collection<Entry<K, V>> create(Object... elements) { 417 return multimapGenerator.create(elements).entries(); 418 } 419 420 @SuppressWarnings("unchecked") 421 @Override createArray(int length)422 public Entry<K, V>[] createArray(int length) { 423 return new Entry[length]; 424 } 425 426 @Override order(List<Entry<K, V>> insertionOrder)427 public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) { 428 return multimapGenerator.order(insertionOrder); 429 } 430 } 431 432 static class ValuesGenerator<K, V, M extends Multimap<K, V>> 433 implements TestCollectionGenerator<V> { 434 private final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator; 435 ValuesGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)436 public ValuesGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) { 437 this.multimapGenerator = multimapGenerator; 438 } 439 440 @Override samples()441 public SampleElements<V> samples() { 442 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 443 .sampleValues(); 444 } 445 446 @Override create(Object... elements)447 public Collection<V> create(Object... elements) { 448 K k = 449 ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 450 .sampleKeys() 451 .e0(); 452 Entry<K, V>[] entries = new Entry[elements.length]; 453 for (int i = 0; i < elements.length; i++) { 454 entries[i] = mapEntry(k, (V) elements[i]); 455 } 456 return multimapGenerator.create((Object[]) entries).values(); 457 } 458 459 @SuppressWarnings("unchecked") 460 @Override createArray(int length)461 public V[] createArray(int length) { 462 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 463 .createValueArray(length); 464 } 465 466 @Override order(List<V> insertionOrder)467 public Iterable<V> order(List<V> insertionOrder) { 468 K k = 469 ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 470 .sampleKeys() 471 .e0(); 472 List<Entry<K, V>> entries = new ArrayList<>(); 473 for (V v : insertionOrder) { 474 entries.add(mapEntry(k, v)); 475 } 476 Iterable<Entry<K, V>> ordered = multimapGenerator.order(entries); 477 List<V> orderedValues = new ArrayList<>(); 478 for (Entry<K, V> entry : ordered) { 479 orderedValues.add(entry.getValue()); 480 } 481 return orderedValues; 482 } 483 } 484 485 static class KeysGenerator<K, V, M extends Multimap<K, V>> 486 implements TestMultisetGenerator<K>, DerivedGenerator { 487 private final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator; 488 KeysGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)489 public KeysGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) { 490 this.multimapGenerator = multimapGenerator; 491 } 492 493 @Override getInnerGenerator()494 public TestSubjectGenerator<?> getInnerGenerator() { 495 return multimapGenerator; 496 } 497 498 @Override samples()499 public SampleElements<K> samples() { 500 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()).sampleKeys(); 501 } 502 503 @Override create(Object... elements)504 public Multiset<K> create(Object... elements) { 505 /* 506 * This is nasty and complicated, but it's the only way to make sure keys get mapped to enough 507 * distinct values. 508 */ 509 Entry[] entries = new Entry[elements.length]; 510 Map<K, Iterator<V>> valueIterators = new HashMap<>(); 511 for (int i = 0; i < elements.length; i++) { 512 @SuppressWarnings("unchecked") 513 K key = (K) elements[i]; 514 515 Iterator<V> valueItr = valueIterators.get(key); 516 if (valueItr == null) { 517 valueIterators.put(key, valueItr = sampleValuesIterator()); 518 } 519 entries[i] = mapEntry((K) elements[i], valueItr.next()); 520 } 521 return multimapGenerator.create((Object[]) entries).keys(); 522 } 523 sampleValuesIterator()524 private Iterator<V> sampleValuesIterator() { 525 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 526 .sampleValues() 527 .iterator(); 528 } 529 530 @SuppressWarnings("unchecked") 531 @Override createArray(int length)532 public K[] createArray(int length) { 533 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 534 .createKeyArray(length); 535 } 536 537 @Override order(List<K> insertionOrder)538 public Iterable<K> order(List<K> insertionOrder) { 539 Iterator<V> valueIter = sampleValuesIterator(); 540 List<Entry<K, V>> entries = new ArrayList<>(); 541 for (K k : insertionOrder) { 542 entries.add(mapEntry(k, valueIter.next())); 543 } 544 Iterable<Entry<K, V>> ordered = multimapGenerator.order(entries); 545 List<K> orderedValues = new ArrayList<>(); 546 for (Entry<K, V> entry : ordered) { 547 orderedValues.add(entry.getKey()); 548 } 549 return orderedValues; 550 } 551 } 552 553 static class MultimapGetGenerator<K, V, M extends Multimap<K, V>> 554 implements TestCollectionGenerator<V> { 555 final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator; 556 MultimapGetGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)557 public MultimapGetGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) { 558 this.multimapGenerator = multimapGenerator; 559 } 560 561 @Override samples()562 public SampleElements<V> samples() { 563 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 564 .sampleValues(); 565 } 566 567 @Override createArray(int length)568 public V[] createArray(int length) { 569 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 570 .createValueArray(length); 571 } 572 573 @Override order(List<V> insertionOrder)574 public Iterable<V> order(List<V> insertionOrder) { 575 K k = 576 ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 577 .sampleKeys() 578 .e0(); 579 List<Entry<K, V>> entries = new ArrayList<>(); 580 for (V v : insertionOrder) { 581 entries.add(mapEntry(k, v)); 582 } 583 Iterable<Entry<K, V>> orderedEntries = multimapGenerator.order(entries); 584 List<V> values = new ArrayList<>(); 585 for (Entry<K, V> entry : orderedEntries) { 586 values.add(entry.getValue()); 587 } 588 return values; 589 } 590 591 @Override create(Object... elements)592 public Collection<V> create(Object... elements) { 593 Entry<K, V>[] array = multimapGenerator.createArray(elements.length); 594 K k = 595 ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 596 .sampleKeys() 597 .e0(); 598 for (int i = 0; i < elements.length; i++) { 599 array[i] = mapEntry(k, (V) elements[i]); 600 } 601 return multimapGenerator.create((Object[]) array).get(k); 602 } 603 } 604 605 static class MultimapAsMapGetGenerator<K, V, M extends Multimap<K, V>> 606 extends MultimapGetGenerator<K, V, M> { 607 MultimapAsMapGetGenerator( OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)608 public MultimapAsMapGetGenerator( 609 OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) { 610 super(multimapGenerator); 611 } 612 613 @Override create(Object... elements)614 public Collection<V> create(Object... elements) { 615 Entry<K, V>[] array = multimapGenerator.createArray(elements.length); 616 K k = 617 ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 618 .sampleKeys() 619 .e0(); 620 for (int i = 0; i < elements.length; i++) { 621 array[i] = mapEntry(k, (V) elements[i]); 622 } 623 return multimapGenerator.create((Object[]) array).asMap().get(k); 624 } 625 } 626 627 private static class ReserializedMultimapGenerator<K, V, M extends Multimap<K, V>> 628 implements TestMultimapGenerator<K, V, M> { 629 private final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator; 630 ReserializedMultimapGenerator( OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)631 public ReserializedMultimapGenerator( 632 OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) { 633 this.multimapGenerator = multimapGenerator; 634 } 635 636 @Override samples()637 public SampleElements<Entry<K, V>> samples() { 638 return multimapGenerator.samples(); 639 } 640 641 @Override createArray(int length)642 public Entry<K, V>[] createArray(int length) { 643 return multimapGenerator.createArray(length); 644 } 645 646 @Override order(List<Entry<K, V>> insertionOrder)647 public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) { 648 return multimapGenerator.order(insertionOrder); 649 } 650 651 @Override create(Object... elements)652 public M create(Object... elements) { 653 return SerializableTester.reserialize( 654 ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 655 .create(elements)); 656 } 657 658 @Override createKeyArray(int length)659 public K[] createKeyArray(int length) { 660 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 661 .createKeyArray(length); 662 } 663 664 @Override createValueArray(int length)665 public V[] createValueArray(int length) { 666 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 667 .createValueArray(length); 668 } 669 670 @Override sampleKeys()671 public SampleElements<K> sampleKeys() { 672 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()).sampleKeys(); 673 } 674 675 @Override sampleValues()676 public SampleElements<V> sampleValues() { 677 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 678 .sampleValues(); 679 } 680 681 @Override createCollection(Iterable<? extends V> values)682 public Collection<V> createCollection(Iterable<? extends V> values) { 683 return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()) 684 .createCollection(values); 685 } 686 } 687 } 688