001/* 002 * ModeShape (http://www.modeshape.org) 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 */ 016package org.modeshape.common.collection; 017 018import static org.hamcrest.core.Is.is; 019import static org.junit.Assert.assertEquals; 020import static org.junit.Assert.assertFalse; 021import static org.junit.Assert.assertNotEquals; 022import static org.junit.Assert.assertThat; 023import static org.junit.Assert.assertTrue; 024import java.util.ArrayList; 025import java.util.Arrays; 026import java.util.Collection; 027import java.util.Collections; 028import java.util.HashSet; 029import java.util.Iterator; 030import java.util.List; 031import java.util.Map; 032import java.util.Set; 033import org.junit.After; 034import org.junit.Before; 035import org.junit.Test; 036import org.modeshape.common.FixFor; 037 038public abstract class AbstractMultimapTest { 039 040 protected Multimap<String, String> multimap; 041 protected String[] keys; 042 protected String[] values; 043 044 @Before 045 public void beforeEach() { 046 multimap = createMultimap(); 047 keys = new String[] {"key1", "key2", "key3", "key4"}; 048 values = new String[] {"value1", "value2", "value3", "value4", "value5", "value6"}; 049 } 050 051 @After 052 public void afterEach() { 053 multimap = null; 054 } 055 056 protected abstract <K, V> Multimap<K, V> createMultimap(); 057 058 protected abstract boolean valuesAllowDuplicates(); 059 060 @Test 061 public void shouldBeEmptyAfterCreation() { 062 assertThat(multimap.isEmpty(), is(true)); 063 } 064 065 @Test 066 public void shouldHaveZeroSizeAfterCreation() { 067 assertThat(multimap.size(), is(0)); 068 } 069 070 @Test 071 public void shouldNotBeEmptyAfterAddingKeyValuePairToEmptyCollection() { 072 multimap.put(keys[0], values[0]); 073 assertThat(multimap.isEmpty(), is(false)); 074 assertThat(multimap.size(), is(1)); 075 assertKeys(multimap, keys[0]); 076 assertValues(multimap, keys[0], values[0]); 077 assertEntries(multimap, entry(keys[0], values[0])); 078 } 079 080 @Test 081 public void shouldNotBeEmptyAfterAddingKeyAndTwoValuesToEmptyCollection() { 082 multimap.put(keys[0], values[0]); 083 multimap.put(keys[0], values[1]); 084 assertThat(multimap.isEmpty(), is(false)); 085 assertThat(multimap.size(), is(2)); 086 assertKeys(multimap, keys[0]); 087 assertValues(multimap, keys[0], values[0], values[1]); 088 assertEntries(multimap, entry(keys[0], values[0]), entry(keys[0], values[1])); 089 } 090 091 @Test 092 public void shouldNotBeEmptyAfterAddingMultipleKeyValuePairsToEmptyCollection() { 093 multimap.put(keys[0], values[0]); 094 multimap.put(keys[1], values[1]); 095 assertThat(multimap.isEmpty(), is(false)); 096 assertThat(multimap.size(), is(2)); 097 assertKeys(multimap, keys[0], keys[1]); 098 assertValues(multimap, keys[0], values[0]); 099 assertValues(multimap, keys[1], values[1]); 100 assertEntries(multimap, entry(keys[0], values[0]), entry(keys[1], values[1])); 101 } 102 103 @Test 104 public void shouldNotBeEmptyAfterAddingMultipleKeyValuePairsMultipleTimesToEmptyCollection() { 105 for (int i = 0; i != 3; ++i) { 106 multimap.put(keys[0], values[0]); 107 multimap.put(keys[1], values[1]); 108 } 109 if (valuesAllowDuplicates()) { 110 assertThat(multimap.isEmpty(), is(false)); 111 assertThat(multimap.size(), is(6)); 112 assertKeys(multimap, keys[0], keys[1]); 113 assertValues(multimap, keys[0], values[0], values[0], values[0]); 114 assertValues(multimap, keys[1], values[1], values[1], values[1]); 115 Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>(); 116 for (int i = 0; i != 3; ++i) { 117 entries.add(entry(keys[0], values[0])); 118 entries.add(entry(keys[1], values[1])); 119 } 120 assertEntries(multimap, entries); 121 } else { 122 assertThat(multimap.isEmpty(), is(false)); 123 assertThat(multimap.size(), is(2)); 124 assertKeys(multimap, keys[0], keys[1]); 125 assertValues(multimap, keys[0], values[0]); 126 assertValues(multimap, keys[1], values[1]); 127 assertEntries(multimap, entry(keys[0], values[0]), entry(keys[1], values[1])); 128 } 129 } 130 131 @Test 132 public void shouldAllowAddingToCollectionOfValues() { 133 multimap.put(keys[0], values[0]); 134 Collection<String> vals = multimap.get(keys[0]); 135 vals.add(values[1]); 136 vals.add(values[2]); 137 assertThat(multimap.isEmpty(), is(false)); 138 assertThat(multimap.size(), is(3)); 139 assertKeys(multimap, keys[0]); 140 assertValues(multimap, keys[0], values[0], values[1], values[2]); 141 assertEntries(multimap, entry(keys[0], values[0]), entry(keys[0], values[1]), entry(keys[0], values[2])); 142 } 143 144 @Test 145 @FixFor("MODE-2743") 146 public void shouldDecrementSizeOnValueIteratorRemove() { 147 assertEquals(0, multimap.size()); 148 assertTrue(multimap.isEmpty()); 149 multimap.put(keys[0], values[0]); 150 assertEquals(1, multimap.size()); 151 Iterator<String> iterator = multimap.get(keys[0]).iterator(); 152 iterator.next(); 153 iterator.remove(); 154 assertEquals(0, multimap.size()); 155 assertTrue(multimap.isEmpty()); 156 } 157 158 @Test 159 public void shouldIterateSuccessfullyWithRemoval() { 160 for (String v : values) { 161 multimap.put(keys[0], v); 162 } 163 for (Iterator<String> iter = multimap.get(keys[0]).iterator(); iter.hasNext();) { 164 iter.next(); 165 iter.remove(); 166 } 167 assertTrue(multimap.isEmpty()); 168 } 169 170 @Test 171 public void shouldSuccessfullyRemoveLastElementFromValueCollection() { 172 multimap.put(keys[0], values[0]); 173 Collection<String> collection = multimap.get(keys[0]); 174 assertTrue(collection.contains(values[0])); 175 176 assertTrue(collection.remove(values[0])); 177 assertFalse(collection.contains(values[0])); 178 assertTrue(collection.isEmpty()); 179 assertEquals(0, collection.size()); 180 assertTrue(multimap.isEmpty()); 181 assertEquals(0, multimap.size()); 182 183 assertFalse(collection.remove(values[0])); 184 assertFalse(collection.contains(values[0])); 185 assertTrue(collection.isEmpty()); 186 assertEquals(0, collection.size()); 187 assertTrue(multimap.isEmpty()); 188 assertEquals(0, multimap.size()); 189 } 190 191 @Test 192 public void shouldSuccessfullyAddValueToValueCollection() { 193 multimap.put(keys[0], values[0]); 194 Collection<String> collection = multimap.get(keys[0]); 195 assertEquals(1, collection.size()); 196 assertFalse(collection.isEmpty()); 197 assertEquals(1, multimap.size()); 198 assertFalse(multimap.isEmpty()); 199 200 assertTrue(collection.add(values[1])); 201 assertEquals(2, collection.size()); 202 assertFalse(collection.isEmpty()); 203 assertEquals(2, multimap.size()); 204 assertFalse(multimap.isEmpty()); 205 } 206 207 @Test 208 public void shouldSuccessfullyAddValueToEmptyValueCollection() { 209 Collection<String> collection = multimap.get(keys[0]); 210 211 assertTrue(collection.add(values[0])); 212 assertTrue(collection.contains(values[0])); 213 assertFalse(collection.isEmpty()); 214 assertEquals(1, collection.size()); 215 assertFalse(multimap.isEmpty()); 216 assertEquals(1, multimap.size()); 217 } 218 219 @Test 220 public void shouldSuccessfullyAddValueToEmptiedValueCollection() { 221 multimap.put(keys[0], values[0]); 222 Collection<String> collection = multimap.get(keys[0]); 223 224 assertTrue(collection.remove(values[0])); 225 assertFalse(collection.contains(values[0])); 226 assertTrue(collection.isEmpty()); 227 assertEquals(0, collection.size()); 228 assertTrue(multimap.isEmpty()); 229 assertEquals(0, multimap.size()); 230 231 assertTrue(collection.add(values[0])); 232 assertTrue(collection.contains(values[0])); 233 assertFalse(collection.isEmpty()); 234 assertEquals(1, collection.size()); 235 assertFalse(multimap.isEmpty()); 236 assertEquals(1, multimap.size()); 237 } 238 239 @Test 240 public void shouldSuccessfullyRemoveAllFromValueCollection() { 241 multimap.put(keys[0], values[0]); 242 Collection<String> collection = multimap.get(keys[0]); 243 244 assertTrue(collection.removeAll(Arrays.asList(values))); 245 assertTrue(collection.isEmpty()); 246 assertEquals(0, collection.size()); 247 assertTrue(multimap.isEmpty()); 248 assertEquals(0, multimap.size()); 249 250 assertFalse(collection.removeAll(Arrays.asList(values))); 251 assertTrue(collection.isEmpty()); 252 assertEquals(0, collection.size()); 253 assertTrue(multimap.isEmpty()); 254 assertEquals(0, multimap.size()); 255 } 256 257 @Test 258 public void shouldSuccessfullyAddAllToValueCollection() { 259 multimap.put(keys[0], values[0]); 260 Collection<String> collection = multimap.get(keys[0]); 261 262 collection.addAll(Arrays.asList(values)); 263 264 int expectedNumberOfValues = values.length; 265 if (valuesAllowDuplicates()) { 266 expectedNumberOfValues++; 267 } 268 269 assertEquals(expectedNumberOfValues, collection.size()); 270 assertFalse(collection.isEmpty()); 271 272 assertEquals(expectedNumberOfValues, multimap.size()); 273 assertFalse(multimap.isEmpty()); 274 } 275 276 @Test 277 public void shouldSuccessfullyClearValueCollection() { 278 multimap.put(keys[0], values[0]); 279 Collection<String> collection = multimap.get(keys[0]); 280 281 collection.clear(); 282 assertTrue(collection.isEmpty()); 283 assertEquals(0, collection.size()); 284 assertTrue(multimap.isEmpty()); 285 assertEquals(0, multimap.size()); 286 287 collection.clear(); 288 assertTrue(collection.isEmpty()); 289 assertEquals(0, collection.size()); 290 assertTrue(multimap.isEmpty()); 291 assertEquals(0, multimap.size()); 292 } 293 294 @Test 295 public void shouldSuccessfullyAddAllToEmptyValueCollection() { 296 Collection<String> collection = multimap.get(keys[0]); 297 298 assertTrue(collection.addAll(Arrays.asList(values))); 299 assertEquals(values.length, collection.size()); 300 assertFalse(collection.isEmpty()); 301 assertEquals(values.length, multimap.size()); 302 assertFalse(multimap.isEmpty()); 303 } 304 305 @Test 306 public void shouldSuccessfullyAddAllToEmptiedValueCollection() { 307 multimap.put(keys[0], values[0]); 308 Collection<String> collection = multimap.get(keys[0]); 309 collection.clear(); 310 311 assertTrue(collection.addAll(Arrays.asList(values))); 312 assertEquals(values.length, collection.size()); 313 assertFalse(collection.isEmpty()); 314 assertEquals(values.length, multimap.size()); 315 assertFalse(multimap.isEmpty()); 316 } 317 318 @Test 319 public void shouldRetainAllInValueCollection() { 320 for (String value : values) { 321 multimap.put(keys[0], value); 322 } 323 assertEquals(values.length, multimap.size()); 324 Collection<String> collection = multimap.get(keys[0]); 325 assertEquals(values.length, collection.size()); 326 327 assertFalse(collection.retainAll(Arrays.asList(values))); 328 assertEquals(values.length, multimap.size()); 329 assertEquals(values.length, collection.size()); 330 331 assertTrue(collection.retainAll(Collections.singleton(values[0]))); 332 assertEquals(1, multimap.size()); 333 assertEquals(1, collection.size()); 334 } 335 336 @Test 337 public void shouldRetainNoneInValueCollection() { 338 for (String value : values) { 339 multimap.put(keys[0], value); 340 } 341 assertEquals(values.length, multimap.size()); 342 Collection<String> collection = multimap.get(keys[0]); 343 assertEquals(values.length, collection.size()); 344 345 assertTrue(collection.retainAll(Collections.emptySet())); 346 assertTrue(multimap.isEmpty()); 347 assertEquals(0, multimap.size()); 348 assertTrue(collection.isEmpty()); 349 assertEquals(0, collection.size()); 350 } 351 352 @Test 353 public void shouldSuccessfullyRetainAllInValueCollection() { 354 multimap.put(keys[0], values[0]); 355 Collection<String> collection = multimap.get(keys[0]); 356 357 assertFalse(collection.retainAll(Arrays.asList(values))); 358 assertFalse(collection.isEmpty()); 359 assertEquals(1, collection.size()); 360 assertFalse(multimap.isEmpty()); 361 assertEquals(1, multimap.size()); 362 } 363 364 @Test 365 public void shouldSuccessfullyRetainAllInEmptyValueCollection() { 366 Collection<String> collection = multimap.get(keys[0]); 367 368 assertFalse(collection.retainAll(Arrays.asList(values))); 369 assertTrue(collection.isEmpty()); 370 assertEquals(0, collection.size()); 371 assertTrue(multimap.isEmpty()); 372 assertEquals(0, multimap.size()); 373 } 374 375 @Test 376 public void shouldSuccessfullyRetainAllInEmptiedValueCollection() { 377 multimap.put(keys[0], values[0]); 378 Collection<String> collection = multimap.get(keys[0]); 379 collection.clear(); 380 381 assertFalse(collection.retainAll(Arrays.asList(values))); 382 assertTrue(collection.isEmpty()); 383 assertEquals(0, collection.size()); 384 assertTrue(multimap.isEmpty()); 385 assertEquals(0, multimap.size()); 386 } 387 388 @Test 389 public void shouldProduceHashCodeOfEmptyValueCollection() { 390 multimap.get(keys[0]).hashCode(); 391 } 392 393 @Test 394 public void shouldProduceHashCodeOfEmptiedValueCollection() { 395 multimap.put(keys[0], values[0]); 396 Collection<String> collection = multimap.get(keys[0]); 397 collection.clear(); 398 collection.hashCode(); 399 } 400 401 @Test 402 public void shouldCompareEqualityOfEmptyValueCollection() { 403 Collection<String> collection = multimap.get(keys[0]); 404 405 assertNotEquals(this, collection); 406 assertNotEquals(collection, this); 407 if (collection instanceof List<?>) { 408 assertEquals(Collections.emptyList(), collection); 409 assertEquals(collection, Collections.emptyList()); 410 } else if (collection instanceof Set<?>) { 411 assertEquals(Collections.emptySet(), collection); 412 assertEquals(collection, Collections.emptySet()); 413 } 414 } 415 416 @Test 417 public void shouldCompareEqualityOfEmptiedValueCollection() { 418 multimap.put(keys[0], values[0]); 419 Collection<String> collection = multimap.get(keys[0]); 420 collection.clear(); 421 422 assertNotEquals(this, collection); 423 assertNotEquals(collection, this); 424 if (collection instanceof List<?>) { 425 assertEquals(Collections.emptyList(), collection); 426 assertEquals(collection, Collections.emptyList()); 427 } else if (collection instanceof Set<?>) { 428 assertEquals(Collections.emptySet(), collection); 429 assertEquals(collection, Collections.emptySet()); 430 } 431 } 432 433 protected <K, V> Map.Entry<K, V> entry( K key, 434 V value ) { 435 return new ImmutableMapEntry<K, V>(key, value); 436 } 437 438 protected <K, V> void assertEntries( Multimap<K, V> multimap, 439 Map.Entry<K, V> entry ) { 440 assertEntries(multimap, java.util.Collections.singletonList(entry)); 441 } 442 443 @SafeVarargs 444 protected final <K, V> void assertEntries( Multimap<K, V> multimap, Map.Entry<K, V>... entries ) { 445 assertEntries(multimap, Arrays.asList(entries)); 446 } 447 448 protected <K, V> void assertEntries( Multimap<K, V> multimap, 449 Collection<Map.Entry<K, V>> entries ) { 450 Collection<Map.Entry<K, V>> actualEntries = multimap.entries(); 451 assertThat(actualEntries.size(), is(entries.size())); 452 assertThat(actualEntries.containsAll(entries), is(true)); 453 assertThat(entries.containsAll(actualEntries), is(true)); 454 } 455 456 protected <K, V> void assertKeys( Multimap<K, V> multimap, 457 K key ) { 458 assertKeys(multimap, java.util.Collections.singletonList(key)); 459 } 460 461 @SafeVarargs 462 protected final <K, V> void assertKeys( Multimap<K, V> multimap, K... keys ) { 463 assertKeys(multimap, Arrays.asList(keys)); 464 } 465 466 protected <K, V> void assertKeys( Multimap<K, V> multimap, 467 Collection<K> expectedKeys ) { 468 Set<K> actualKeys = multimap.keySet(); 469 assertThat(actualKeys.size(), is(expectedKeys.size())); 470 assertThat(actualKeys.containsAll(expectedKeys), is(true)); 471 assertThat(expectedKeys.containsAll(actualKeys), is(true)); 472 } 473 474 protected <K, V> void assertValues( Multimap<K, V> multimap, 475 K key, 476 V value ) { 477 Collection<V> expectedValues = null; 478 if (valuesAllowDuplicates()) { 479 expectedValues = java.util.Collections.singletonList(value); 480 } else { 481 expectedValues = java.util.Collections.singleton(value); 482 } 483 assertValues(multimap, key, expectedValues); 484 } 485 486 @SafeVarargs 487 protected final <K, V> void assertValues( Multimap<K, V> multimap, K key, V... values ) { 488 Collection<V> expectedValues = null; 489 if (valuesAllowDuplicates()) { 490 expectedValues = Arrays.asList(values); 491 } else { 492 expectedValues = new HashSet<V>(Arrays.asList(values)); 493 } 494 assertValues(multimap, key, expectedValues); 495 } 496 497 protected <K, V> void assertValues( Multimap<K, V> multimap, 498 K key, 499 Collection<V> expectedValues ) { 500 Collection<V> actualValues = multimap.get(key); 501 assertThat(actualValues.size(), is(expectedValues.size())); 502 if (actualValues instanceof List) { 503 assertThat(actualValues, is(expectedValues)); 504 Iterator<V> actualIter = actualValues.iterator(); 505 Iterator<V> expectedIter = expectedValues.iterator(); 506 while (expectedIter.hasNext()) { 507 V actual = actualIter.next(); 508 V expected = expectedIter.next(); 509 assertThat(actual, is(expected)); 510 } 511 } else { 512 assertThat(actualValues.containsAll(expectedValues), is(true)); 513 assertThat(expectedValues.containsAll(actualValues), is(true)); 514 } 515 } 516}