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.assertThat;
020import java.util.ArrayList;
021import java.util.Collection;
022import java.util.List;
023import java.util.ListIterator;
024import java.util.Map;
025import org.junit.Before;
026import org.junit.Test;
027
028public class LinkedListMultimapTest extends AbstractMultimapTest {
029
030    protected ListMultimap<String, String> listMultimap;
031
032    @Override
033    @Before
034    public void beforeEach() {
035        super.beforeEach();
036        listMultimap = (ListMultimap<String, String>)multimap;
037    }
038
039    @Override
040    protected <K, V> LinkedListMultimap<K, V> createMultimap() {
041        return LinkedListMultimap.create();
042    }
043
044    /**
045     * {@inheritDoc}
046     * 
047     * @see org.modeshape.common.collection.AbstractMultimapTest#valuesAllowDuplicates()
048     */
049    @Override
050    protected boolean valuesAllowDuplicates() {
051        return true;
052    }
053
054    @Test
055    public void shouldAddEntryToEmtpyMap() {
056        LinkedListMultimap<String, String> listMap = createMultimap();
057        assertThat(listMap.size(), is(0));
058        listMap.addEntryFor(keys[0], values[0]);
059        assertThat(listMap.size(), is(1));
060    }
061
062    @Test
063    public void shouldMaintainOrderOfInsertionInKeysAndValues() {
064        multimap.put(keys[0], values[0]);
065        multimap.put(keys[1], values[1]);
066        multimap.put(keys[0], values[0]);
067        multimap.put(keys[1], values[2]);
068        multimap.put(keys[0], values[0]);
069        multimap.put(keys[1], values[3]);
070        assertThat(multimap.isEmpty(), is(false));
071        assertThat(multimap.size(), is(6));
072        assertKeys(multimap, keys[0], keys[1]);
073        assertValues(multimap, keys[0], values[0], values[0], values[0]);
074        assertValues(multimap, keys[1], values[1], values[2], values[3]);
075        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
076        entries.add(entry(keys[0], values[0]));
077        entries.add(entry(keys[1], values[1]));
078        entries.add(entry(keys[0], values[0]));
079        entries.add(entry(keys[1], values[2]));
080        entries.add(entry(keys[0], values[0]));
081        entries.add(entry(keys[1], values[3]));
082        assertEntries(multimap, entries);
083    }
084
085    @Test
086    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterRemovalOfFirstKeyValuePair() {
087        multimap.put(keys[0], values[0]);
088        multimap.put(keys[1], values[0]);
089        multimap.put(keys[0], values[1]);
090        multimap.put(keys[1], values[1]);
091        multimap.put(keys[0], values[2]);
092        multimap.put(keys[1], values[2]);
093        multimap.remove(keys[0], values[0]);
094        assertThat(multimap.isEmpty(), is(false));
095        assertThat(multimap.size(), is(5));
096        assertKeys(multimap, keys[0], keys[1]);
097        assertValues(multimap, keys[0], /*values[0],*/values[1], values[2]);
098        assertValues(multimap, keys[1], values[0], values[1], values[2]);
099        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
100        // entries.add(entry(keys[0], values[0]));
101        entries.add(entry(keys[1], values[0]));
102        entries.add(entry(keys[0], values[1]));
103        entries.add(entry(keys[1], values[1]));
104        entries.add(entry(keys[0], values[2]));
105        entries.add(entry(keys[1], values[2]));
106        assertEntries(multimap, entries);
107    }
108
109    @Test
110    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterRemovalOfMiddleKeyValuePair() {
111        multimap.put(keys[0], values[0]);
112        multimap.put(keys[1], values[1]);
113        multimap.put(keys[0], values[0]);
114        multimap.put(keys[1], values[2]);
115        multimap.put(keys[0], values[0]);
116        multimap.put(keys[1], values[3]);
117        multimap.remove(keys[1], values[2]);
118        assertThat(multimap.isEmpty(), is(false));
119        assertThat(multimap.size(), is(5));
120        assertKeys(multimap, keys[0], keys[1]);
121        assertValues(multimap, keys[0], values[0], values[0], values[0]);
122        assertValues(multimap, keys[1], values[1], values[3]);
123        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
124        entries.add(entry(keys[0], values[0]));
125        entries.add(entry(keys[1], values[1]));
126        entries.add(entry(keys[0], values[0]));
127        entries.add(entry(keys[0], values[0]));
128        entries.add(entry(keys[1], values[3]));
129        assertEntries(multimap, entries);
130    }
131
132    @Test
133    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterRemovalOfLastKeyValuePair() {
134        multimap.put(keys[0], values[0]);
135        multimap.put(keys[1], values[0]);
136        multimap.put(keys[0], values[1]);
137        multimap.put(keys[1], values[1]);
138        multimap.put(keys[0], values[2]);
139        multimap.put(keys[1], values[2]);
140        multimap.remove(keys[1], values[2]);
141        assertThat(multimap.isEmpty(), is(false));
142        assertThat(multimap.size(), is(5));
143        assertKeys(multimap, keys[0], keys[1]);
144        assertValues(multimap, keys[0], values[0], values[1], values[2]);
145        assertValues(multimap, keys[1], values[0], values[1] /*, values[2]*/);
146        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
147        entries.add(entry(keys[0], values[0]));
148        entries.add(entry(keys[1], values[0]));
149        entries.add(entry(keys[0], values[1]));
150        entries.add(entry(keys[1], values[1]));
151        entries.add(entry(keys[0], values[2]));
152        // entries.add(entry(keys[1], values[2]));
153        assertEntries(multimap, entries);
154    }
155
156    @Test
157    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterRemovalOfFirstValueFromKeyCollection() {
158        multimap.put(keys[0], values[0]);
159        multimap.put(keys[1], values[0]);
160        multimap.put(keys[0], values[1]);
161        multimap.put(keys[1], values[1]);
162        multimap.put(keys[0], values[2]);
163        multimap.put(keys[1], values[2]);
164        multimap.get(keys[0]).remove(values[0]);
165        assertThat(multimap.isEmpty(), is(false));
166        assertThat(multimap.size(), is(5));
167        assertKeys(multimap, keys[0], keys[1]);
168        assertValues(multimap, keys[0], /*values[0],*/values[1], values[2]);
169        assertValues(multimap, keys[1], values[0], values[1], values[2]);
170        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
171        // entries.add(entry(keys[0], values[0]));
172        entries.add(entry(keys[1], values[0]));
173        entries.add(entry(keys[0], values[1]));
174        entries.add(entry(keys[1], values[1]));
175        entries.add(entry(keys[0], values[2]));
176        entries.add(entry(keys[1], values[2]));
177        assertEntries(multimap, entries);
178    }
179
180    @Test
181    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterRemovalOfMiddleValueFromKeyCollection() {
182        multimap.put(keys[0], values[0]);
183        multimap.put(keys[1], values[0]);
184        multimap.put(keys[0], values[1]);
185        multimap.put(keys[1], values[1]);
186        multimap.put(keys[0], values[2]);
187        multimap.put(keys[1], values[2]);
188        multimap.get(keys[1]).remove(values[1]);
189        assertThat(multimap.isEmpty(), is(false));
190        assertThat(multimap.size(), is(5));
191        assertKeys(multimap, keys[0], keys[1]);
192        assertValues(multimap, keys[0], values[0], values[1], values[2]);
193        assertValues(multimap, keys[1], values[0], values[2]);
194        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
195        entries.add(entry(keys[0], values[0]));
196        entries.add(entry(keys[1], values[0]));
197        entries.add(entry(keys[0], values[1]));
198        entries.add(entry(keys[0], values[2]));
199        entries.add(entry(keys[1], values[2]));
200        assertEntries(multimap, entries);
201    }
202
203    @Test
204    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterRemovalOfLastValueFromKeyCollection() {
205        multimap.put(keys[0], values[0]);
206        multimap.put(keys[1], values[0]);
207        multimap.put(keys[0], values[1]);
208        multimap.put(keys[1], values[1]);
209        multimap.put(keys[0], values[2]);
210        multimap.put(keys[1], values[2]);
211        multimap.get(keys[1]).remove(values[2]);
212        assertThat(multimap.isEmpty(), is(false));
213        assertThat(multimap.size(), is(5));
214        assertKeys(multimap, keys[0], keys[1]);
215        assertValues(multimap, keys[0], values[0], values[1], values[2]);
216        assertValues(multimap, keys[1], values[0], values[1] /*, values[2]*/);
217        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
218        entries.add(entry(keys[0], values[0]));
219        entries.add(entry(keys[1], values[0]));
220        entries.add(entry(keys[0], values[1]));
221        entries.add(entry(keys[1], values[1]));
222        entries.add(entry(keys[0], values[2]));
223        // entries.add(entry(keys[1], values[2]));
224        assertEntries(multimap, entries);
225    }
226
227    @Test
228    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterAddingValueAtBeginngingOfCollectionForKey() {
229        multimap.put(keys[0], values[0]);
230        multimap.put(keys[1], values[0]);
231        multimap.put(keys[0], values[1]);
232        multimap.put(keys[1], values[1]);
233        multimap.put(keys[0], values[2]);
234        multimap.put(keys[1], values[2]);
235        addValueUsingCollection(listMultimap, keys[0], 0, values[3]);
236        assertThat(multimap.isEmpty(), is(false));
237        assertThat(multimap.size(), is(7));
238        assertKeys(multimap, keys[0], keys[1]);
239        assertValues(multimap, keys[0], values[3], values[0], values[1], values[2]);
240        assertValues(multimap, keys[1], values[0], values[1], values[2]);
241        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
242        entries.add(entry(keys[0], values[3]));
243        entries.add(entry(keys[0], values[0]));
244        entries.add(entry(keys[1], values[0]));
245        entries.add(entry(keys[0], values[1]));
246        entries.add(entry(keys[1], values[1]));
247        entries.add(entry(keys[0], values[2]));
248        entries.add(entry(keys[1], values[2]));
249        assertEntries(multimap, entries);
250    }
251
252    @Test
253    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterAddingValueAtMiddleOfCollectionForKey() {
254        multimap.put(keys[0], values[0]);
255        multimap.put(keys[1], values[0]);
256        multimap.put(keys[0], values[1]);
257        multimap.put(keys[1], values[1]);
258        multimap.put(keys[0], values[2]);
259        multimap.put(keys[1], values[2]);
260        addValueUsingCollection(listMultimap, keys[1], 1, values[3]);
261        assertThat(multimap.isEmpty(), is(false));
262        assertThat(multimap.size(), is(7));
263        assertKeys(multimap, keys[0], keys[1]);
264        assertValues(multimap, keys[0], values[0], values[1], values[2]);
265        assertValues(multimap, keys[1], values[0], values[3], values[1], values[2]);
266        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
267        entries.add(entry(keys[0], values[0]));
268        entries.add(entry(keys[1], values[0]));
269        entries.add(entry(keys[0], values[1]));
270        entries.add(entry(keys[1], values[3]));
271        entries.add(entry(keys[1], values[1]));
272        entries.add(entry(keys[0], values[2]));
273        entries.add(entry(keys[1], values[2]));
274        assertEntries(multimap, entries);
275    }
276
277    @Test
278    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterAddingValueAtEndOfCollectionForKey() {
279        multimap.put(keys[0], values[0]);
280        multimap.put(keys[1], values[0]);
281        multimap.put(keys[0], values[1]);
282        multimap.put(keys[1], values[1]);
283        multimap.put(keys[0], values[2]);
284        multimap.put(keys[1], values[2]);
285        addValueUsingCollection(listMultimap, keys[1], 3, values[3]);
286        assertThat(multimap.isEmpty(), is(false));
287        assertThat(multimap.size(), is(7));
288        assertKeys(multimap, keys[0], keys[1]);
289        assertValues(multimap, keys[0], values[0], values[1], values[2]);
290        assertValues(multimap, keys[1], values[0], values[1], values[2], values[3]);
291        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
292        entries.add(entry(keys[0], values[0]));
293        entries.add(entry(keys[1], values[0]));
294        entries.add(entry(keys[0], values[1]));
295        entries.add(entry(keys[1], values[1]));
296        entries.add(entry(keys[0], values[2]));
297        entries.add(entry(keys[1], values[2]));
298        entries.add(entry(keys[1], values[3]));
299        assertEntries(multimap, entries);
300    }
301
302    @Test
303    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterAddingValueAtBeginngingOfCollectionForKeyUsingIterator() {
304        multimap.put(keys[0], values[0]);
305        multimap.put(keys[1], values[0]);
306        multimap.put(keys[0], values[1]);
307        multimap.put(keys[1], values[1]);
308        multimap.put(keys[0], values[2]);
309        multimap.put(keys[1], values[2]);
310        addValueUsingIterator(listMultimap, keys[0], 0, values[3]);
311        assertThat(multimap.isEmpty(), is(false));
312        assertThat(multimap.size(), is(7));
313        assertKeys(multimap, keys[0], keys[1]);
314        assertValues(multimap, keys[0], values[3], values[0], values[1], values[2]);
315        assertValues(multimap, keys[1], values[0], values[1], values[2]);
316        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
317        entries.add(entry(keys[0], values[3]));
318        entries.add(entry(keys[0], values[0]));
319        entries.add(entry(keys[1], values[0]));
320        entries.add(entry(keys[0], values[1]));
321        entries.add(entry(keys[1], values[1]));
322        entries.add(entry(keys[0], values[2]));
323        entries.add(entry(keys[1], values[2]));
324        assertEntries(multimap, entries);
325    }
326
327    @Test
328    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterAddingValueAtMiddleOfCollectionForKeyUsingIterator() {
329        multimap.put(keys[0], values[0]);
330        multimap.put(keys[1], values[0]);
331        multimap.put(keys[0], values[1]);
332        multimap.put(keys[1], values[1]);
333        multimap.put(keys[0], values[2]);
334        multimap.put(keys[1], values[2]);
335        addValueUsingIterator(listMultimap, keys[1], 1, values[3]);
336        assertThat(multimap.isEmpty(), is(false));
337        assertThat(multimap.size(), is(7));
338        assertKeys(multimap, keys[0], keys[1]);
339        assertValues(multimap, keys[0], values[0], values[1], values[2]);
340        assertValues(multimap, keys[1], values[0], values[3], values[1], values[2]);
341        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
342        entries.add(entry(keys[0], values[0]));
343        entries.add(entry(keys[1], values[0]));
344        entries.add(entry(keys[0], values[1]));
345        entries.add(entry(keys[1], values[3]));
346        entries.add(entry(keys[1], values[1]));
347        entries.add(entry(keys[0], values[2]));
348        entries.add(entry(keys[1], values[2]));
349        assertEntries(multimap, entries);
350    }
351
352    @Test
353    public void shouldMaintainOrderOfInsertionInKeysAndValuesAfterAddingValueAtEndOfCollectionForKeyUsingIterator() {
354        multimap.put(keys[0], values[0]);
355        multimap.put(keys[1], values[0]);
356        multimap.put(keys[0], values[1]);
357        multimap.put(keys[1], values[1]);
358        multimap.put(keys[0], values[2]);
359        multimap.put(keys[1], values[2]);
360        addValueUsingIterator(listMultimap, keys[1], 3, values[3]);
361        assertThat(multimap.isEmpty(), is(false));
362        assertThat(multimap.size(), is(7));
363        assertKeys(multimap, keys[0], keys[1]);
364        assertValues(multimap, keys[0], values[0], values[1], values[2]);
365        assertValues(multimap, keys[1], values[0], values[1], values[2], values[3]);
366        Collection<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>();
367        entries.add(entry(keys[0], values[0]));
368        entries.add(entry(keys[1], values[0]));
369        entries.add(entry(keys[0], values[1]));
370        entries.add(entry(keys[1], values[1]));
371        entries.add(entry(keys[0], values[2]));
372        entries.add(entry(keys[1], values[2]));
373        entries.add(entry(keys[1], values[3]));
374        assertEntries(multimap, entries);
375    }
376
377    protected void addValueUsingCollection( ListMultimap<String, String> multimap,
378                                            String key,
379                                            int atPosition,
380                                            String value ) {
381        List<String> values = multimap.get(key);
382        values.add(atPosition, value);
383    }
384
385    protected void addValueUsingIterator( ListMultimap<String, String> multimap,
386                                          String key,
387                                          int atPosition,
388                                          String value ) {
389        List<String> values = multimap.get(key);
390        ListIterator<String> iter = values.listIterator();
391        while (iter.hasNext()) {
392            if (iter.nextIndex() == atPosition) {
393                iter.add(value); // will insert before the 'next' value that was at the 'atPosition' index
394                return;
395            }
396            iter.next();
397        }
398        iter.add(value); // at the end
399    }
400
401    protected void setValueUsingCollection( ListMultimap<String, String> multimap,
402                                            String key,
403                                            int atPosition,
404                                            String value ) {
405        List<String> values = multimap.get(key);
406        values.set(atPosition, value);
407    }
408
409    protected void setValueUsingIterator( ListMultimap<String, String> multimap,
410                                          String key,
411                                          int atPosition,
412                                          String value ) {
413        List<String> values = multimap.get(key);
414        ListIterator<String> iter = values.listIterator();
415        while (iter.hasNext()) {
416            if (iter.nextIndex() == atPosition) {
417                iter.set(value);
418                break;
419            }
420            iter.next();
421        }
422    }
423
424}