• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/db-4.7.25.NC/test/scr024/src/com/sleepycat/collections/test/
1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2002,2008 Oracle.  All rights reserved.
5 *
6 * $Id: CollectionTest.java,v 12.10 2008/02/07 17:12:31 mark Exp $
7 */
8
9package com.sleepycat.collections.test;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.Enumeration;
15import java.util.HashMap;
16import java.util.Iterator;
17import java.util.List;
18import java.util.ListIterator;
19import java.util.Map;
20import java.util.NoSuchElementException;
21import java.util.Set;
22import java.util.SortedMap;
23import java.util.SortedSet;
24
25import junit.framework.Test;
26import junit.framework.TestCase;
27import junit.framework.TestSuite;
28
29import com.sleepycat.bind.EntityBinding;
30import com.sleepycat.bind.EntryBinding;
31import com.sleepycat.collections.MapEntryParameter;
32import com.sleepycat.collections.StoredCollection;
33import com.sleepycat.collections.StoredCollections;
34import com.sleepycat.collections.StoredContainer;
35import com.sleepycat.collections.StoredEntrySet;
36import com.sleepycat.collections.StoredIterator;
37import com.sleepycat.collections.StoredKeySet;
38import com.sleepycat.collections.StoredList;
39import com.sleepycat.collections.StoredMap;
40import com.sleepycat.collections.StoredSortedEntrySet;
41import com.sleepycat.collections.StoredSortedKeySet;
42import com.sleepycat.collections.StoredSortedMap;
43import com.sleepycat.collections.StoredSortedValueSet;
44import com.sleepycat.collections.StoredValueSet;
45import com.sleepycat.collections.TransactionRunner;
46import com.sleepycat.collections.TransactionWorker;
47import com.sleepycat.compat.DbCompat;
48import com.sleepycat.db.Database;
49import com.sleepycat.db.DatabaseException;
50import com.sleepycat.db.Environment;
51import com.sleepycat.util.ExceptionUnwrapper;
52import com.sleepycat.util.test.SharedTestUtils;
53import com.sleepycat.util.test.TestEnv;
54
55/**
56 * @author Mark Hayes
57 */
58public class CollectionTest extends TestCase {
59
60    private static final int NONE = 0;
61    private static final int SUB = 1;
62    private static final int HEAD = 2;
63    private static final int TAIL = 3;
64
65    /*
66     * For long tests we permute testStoredIterator to test both StoredIterator
67     * and BlockIterator.  When testing BlockIterator, we permute the maxKey
68     * over the array values below.  BlockIterator's block size is 10.  So we
69     * test below the block size (6), at the block size (10), and above it (14
70     * and 22).
71     */
72    private static final int DEFAULT_MAX_KEY = 6;
73    private static final int[] MAX_KEYS = {6, 10, 14, 22};
74
75    private boolean testStoredIterator;
76    private int maxKey; /* Must be a multiple of 2. */
77    private int beginKey = 1;
78    private int endKey;
79
80    private Environment env;
81    private Database store;
82    private Database index;
83    private boolean isEntityBinding;
84    private boolean isAutoCommit;
85    private TestStore testStore;
86    private String testName;
87    private EntryBinding keyBinding;
88    private EntryBinding valueBinding;
89    private EntityBinding entityBinding;
90    private TransactionRunner readRunner;
91    private TransactionRunner writeRunner;
92    private TransactionRunner writeIterRunner;
93    private TestEnv testEnv;
94
95    private StoredMap map;
96    private StoredMap imap; // insertable map (primary store for indexed map)
97    private StoredSortedMap smap; // sorted map (null or equal to map)
98    private StoredMap saveMap;
99    private StoredSortedMap saveSMap;
100    private int rangeType;
101    private StoredList list;
102    private StoredList ilist; // insertable list (primary store for index list)
103    private StoredList saveList;
104    private StoredKeySet keySet;
105    private StoredValueSet valueSet;
106
107    /**
108     * Runs a command line collection test.
109     * @see #usage
110     */
111    public static void main(String[] args)
112        throws Exception {
113
114        if (args.length == 1 &&
115            (args[0].equals("-h") || args[0].equals("-help"))) {
116            usage();
117        } else {
118            junit.framework.TestResult tr =
119		junit.textui.TestRunner.run(suite(args));
120	    if (tr.errorCount() > 0 ||
121		tr.failureCount() > 0) {
122		System.exit(1);
123	    } else {
124		System.exit(0);
125	    }
126        }
127    }
128
129    private static void usage() {
130
131        System.out.println(
132            "Usage: java com.sleepycat.collections.test.CollectionTest\n" +
133            "              -h | -help\n" +
134            "              [testName]...\n" +
135            "  where testName has the format:\n" +
136            "    <env>-<store>-{entity|value}\n" +
137            "  <env> is:\n" +
138            "    bdb | cdb | txn\n" +
139            "  <store> is:\n" +
140            "    btree-uniq | btree-dup | btree-dupsort | btree-recnum |\n" +
141            "    hash-uniq | hash-dup | hash-dupsort |\n" +
142            "    queue | recno | recno-renum\n" +
143            "  For example:  bdb-btree-uniq-entity\n" +
144            "  If no arguments are given then all tests are run.");
145        System.exit(2);
146    }
147
148    public static Test suite()
149        throws Exception {
150
151        return suite(null);
152    }
153
154    static Test suite(String[] args)
155        throws Exception {
156
157        if (SharedTestUtils.runLongTests()) {
158            TestSuite suite = new TestSuite();
159
160            /* StoredIterator tests. */
161            permuteTests(args, suite, true, DEFAULT_MAX_KEY);
162
163            /* BlockIterator tests with different maxKey values. */
164            for (int i = 0; i < MAX_KEYS.length; i += 1) {
165                permuteTests(args, suite, false, MAX_KEYS[i]);
166            }
167
168            return suite;
169        } else {
170            return baseSuite(args);
171        }
172    }
173
174    private static void permuteTests(String[] args,
175                                     TestSuite suite,
176                                     boolean storedIter,
177                                     int maxKey)
178        throws Exception {
179
180        TestSuite baseTests = baseSuite(args);
181        Enumeration e = baseTests.tests();
182        while (e.hasMoreElements()) {
183            CollectionTest t = (CollectionTest) e.nextElement();
184            t.setParams(storedIter, maxKey);
185            suite.addTest(t);
186        }
187    }
188
189    private static TestSuite baseSuite(String[] args)
190        throws Exception {
191
192        TestSuite suite = new TestSuite();
193        for (int i = 0; i < TestEnv.ALL.length; i += 1) {
194            for (int j = 0; j < TestStore.ALL.length; j += 1) {
195                for (int k = 0; k < 2; k += 1) {
196                    boolean entityBinding = (k != 0);
197
198                    addTest(args, suite, new CollectionTest(
199                            TestEnv.ALL[i], TestStore.ALL[j],
200                            entityBinding, false));
201
202                    if (TestEnv.ALL[i].isTxnMode()) {
203                        addTest(args, suite, new CollectionTest(
204                                TestEnv.ALL[i], TestStore.ALL[j],
205                                entityBinding, true));
206                    }
207                }
208            }
209        }
210        return suite;
211    }
212
213    private static void addTest(String[] args, TestSuite suite,
214                                CollectionTest test) {
215
216        if (args == null || args.length == 0) {
217            suite.addTest(test);
218        } else {
219            for (int t = 0; t < args.length; t += 1) {
220                if (args[t].equals(test.testName)) {
221                    suite.addTest(test);
222                    break;
223                }
224            }
225        }
226    }
227
228    public CollectionTest(TestEnv testEnv, TestStore testStore,
229                          boolean isEntityBinding, boolean isAutoCommit) {
230
231        super(null);
232
233        this.testEnv = testEnv;
234        this.testStore = testStore;
235        this.isEntityBinding = isEntityBinding;
236        this.isAutoCommit = isAutoCommit;
237
238        keyBinding = testStore.getKeyBinding();
239        valueBinding = testStore.getValueBinding();
240        entityBinding = testStore.getEntityBinding();
241
242        setParams(false, DEFAULT_MAX_KEY);
243    }
244
245    private void setParams(boolean storedIter, int maxKey) {
246
247        this.testStoredIterator = storedIter;
248        this.maxKey = maxKey;
249        this.endKey = maxKey;
250
251        testName = testEnv.getName() + '-' + testStore.getName() +
252                    (isEntityBinding ? "-entity" : "-value") +
253                    (isAutoCommit ? "-autoCommit" : "") +
254                    (testStoredIterator ? "-storedIter" : "") +
255                    ((maxKey != DEFAULT_MAX_KEY) ? ("-maxKey-" + maxKey) : "");
256    }
257
258    public void tearDown()
259        throws Exception {
260
261        setName(testName);
262    }
263
264    public void runTest()
265        throws Exception {
266
267        SharedTestUtils.printTestName(SharedTestUtils.qualifiedTestName(this));
268        try {
269            env = testEnv.open(testName);
270
271            // For testing auto-commit, use a normal (transactional) runner for
272            // all reading and for writing via an iterator, and a do-nothing
273            // runner for writing via collections; if auto-commit is tested,
274            // the per-collection auto-commit property will be set elsewhere.
275            //
276            TransactionRunner normalRunner = newTransactionRunner(env);
277            normalRunner.setAllowNestedTransactions(
278                    DbCompat.NESTED_TRANSACTIONS);
279            TransactionRunner nullRunner = new NullTransactionRunner(env);
280            readRunner = nullRunner;
281            if (isAutoCommit) {
282                writeRunner = nullRunner;
283                writeIterRunner = testStoredIterator ? normalRunner
284                                                     : nullRunner;
285            } else {
286                writeRunner = normalRunner;
287                writeIterRunner = normalRunner;
288            }
289
290            store = testStore.open(env, "unindexed.db");
291            testUnindexed();
292            store.close();
293            store = null;
294
295            TestStore indexOf = testStore.getIndexOf();
296            if (indexOf != null) {
297                store = indexOf.open(env, "indexed.db");
298                index = testStore.openIndex(store, "index.db");
299                testIndexed();
300                index.close();
301                index = null;
302                store.close();
303                store = null;
304            }
305            env.close();
306            env = null;
307        } catch (Exception e) {
308            throw ExceptionUnwrapper.unwrap(e);
309        } finally {
310            if (index != null) {
311                try {
312		    index.close();
313		} catch (Exception e) {
314		}
315            }
316            if (store != null) {
317                try {
318		    store.close();
319		} catch (Exception e) {
320		}
321            }
322            if (env != null) {
323                try {
324		    env.close();
325		} catch (Exception e) {
326		}
327            }
328            /* Ensure that GC can cleanup. */
329            index = null;
330            store = null;
331            env = null;
332            readRunner = null;
333            writeRunner = null;
334            writeIterRunner = null;
335            map = null;
336            imap = null;
337            smap = null;
338            saveMap = null;
339            saveSMap = null;
340            list = null;
341            ilist = null;
342            saveList = null;
343            keySet = null;
344            valueSet = null;
345	    testEnv = null;
346	    testStore = null;
347        }
348    }
349
350    /**
351     * Is overridden in XACollectionTest.
352     */
353    protected TransactionRunner newTransactionRunner(Environment env)
354        throws DatabaseException {
355
356        return new TransactionRunner(env);
357    }
358
359    void testCreation(StoredContainer cont, int expectSize)
360        throws Exception {
361
362        assertEquals(index != null, cont.isSecondary());
363        assertEquals(testStore.isOrdered(), cont.isOrdered());
364        assertEquals(testStore.areKeyRangesAllowed(),
365                     cont.areKeyRangesAllowed());
366        assertEquals(testStore.areKeysRenumbered(), cont.areKeysRenumbered());
367        assertEquals(testStore.areDuplicatesAllowed(),
368                     cont.areDuplicatesAllowed());
369        assertEquals(testEnv.isTxnMode(), cont.isTransactional());
370        assertEquals(expectSize, cont.size());
371    }
372
373    void testMapCreation(Map map)
374        throws Exception {
375
376        assertTrue(map.values() instanceof Set);
377        assertEquals(testStore.areKeyRangesAllowed(),
378                     map.keySet() instanceof SortedSet);
379        assertEquals(testStore.areKeyRangesAllowed(),
380                     map.entrySet() instanceof SortedSet);
381        assertEquals(testStore.areKeyRangesAllowed() && isEntityBinding,
382                     map.values() instanceof SortedSet);
383    }
384
385    void testUnindexed()
386        throws Exception {
387
388        // create primary map
389        if (testStore.areKeyRangesAllowed()) {
390            if (isEntityBinding) {
391                smap = new StoredSortedMap(store, keyBinding,
392                                           entityBinding,
393                                           testStore.getKeyAssigner());
394                valueSet = new StoredSortedValueSet(store, entityBinding,
395                                                    true);
396            } else {
397                smap = new StoredSortedMap(store, keyBinding,
398                                           valueBinding,
399                                           testStore.getKeyAssigner());
400                // sorted value set is not possible since key cannot be derived
401                // for performing subSet, etc.
402            }
403            keySet = new StoredSortedKeySet(store, keyBinding, true);
404            map = smap;
405        } else {
406            if (isEntityBinding) {
407                map = new StoredMap(store, keyBinding, entityBinding,
408                                    testStore.getKeyAssigner());
409                valueSet = new StoredValueSet(store, entityBinding, true);
410            } else {
411                map = new StoredMap(store, keyBinding, valueBinding,
412                                    testStore.getKeyAssigner());
413                valueSet = new StoredValueSet(store, valueBinding, true);
414            }
415            smap = null;
416            keySet = new StoredKeySet(store, keyBinding, true);
417        }
418        imap = map;
419
420        // create primary list
421        if (testStore.hasRecNumAccess()) {
422            if (isEntityBinding) {
423                ilist = new StoredList(store, entityBinding,
424                                       testStore.getKeyAssigner());
425            } else {
426                ilist = new StoredList(store, valueBinding,
427                                       testStore.getKeyAssigner());
428            }
429            list = ilist;
430        } else {
431            try {
432                if (isEntityBinding) {
433                    ilist = new StoredList(store, entityBinding,
434                                           testStore.getKeyAssigner());
435                } else {
436                    ilist = new StoredList(store, valueBinding,
437                                           testStore.getKeyAssigner());
438                }
439                fail();
440            } catch (IllegalArgumentException expected) {}
441        }
442
443        testCreation(map, 0);
444        if (list != null) {
445            testCreation(list, 0);
446        }
447        testMapCreation(map);
448        addAll();
449        testAll();
450    }
451
452    void testIndexed()
453        throws Exception {
454
455        // create primary map
456        if (isEntityBinding) {
457            map = new StoredMap(store, keyBinding, entityBinding,
458                                testStore.getKeyAssigner());
459        } else {
460            map = new StoredMap(store, keyBinding, valueBinding,
461                                testStore.getKeyAssigner());
462        }
463        imap = map;
464        smap = null;
465        // create primary list
466        if (testStore.hasRecNumAccess()) {
467            if (isEntityBinding) {
468                list = new StoredList(store, entityBinding,
469                                      testStore.getKeyAssigner());
470            } else {
471                list = new StoredList(store, valueBinding,
472                                      testStore.getKeyAssigner());
473            }
474            ilist = list;
475        }
476
477        addAll();
478        readAll();
479
480        // create indexed map (keySet/valueSet)
481        if (testStore.areKeyRangesAllowed()) {
482            if (isEntityBinding) {
483                map = smap = new StoredSortedMap(index, keyBinding,
484                                                 entityBinding, true);
485                valueSet = new StoredSortedValueSet(index, entityBinding,
486                                                    true);
487            } else {
488                map = smap = new StoredSortedMap(index, keyBinding,
489                                                 valueBinding, true);
490                // sorted value set is not possible since key cannot be derived
491                // for performing subSet, etc.
492            }
493            keySet = new StoredSortedKeySet(index, keyBinding, true);
494        } else {
495            if (isEntityBinding) {
496                map = new StoredMap(index, keyBinding, entityBinding, true);
497                valueSet = new StoredValueSet(index, entityBinding, true);
498            } else {
499                map = new StoredMap(index, keyBinding, valueBinding, true);
500                valueSet = new StoredValueSet(index, valueBinding, true);
501            }
502            smap = null;
503            keySet = new StoredKeySet(index, keyBinding, true);
504        }
505
506        // create indexed list
507        if (testStore.hasRecNumAccess()) {
508            if (isEntityBinding) {
509                list = new StoredList(index, entityBinding, true);
510            } else {
511                list = new StoredList(index, valueBinding, true);
512            }
513        } else {
514            try {
515                if (isEntityBinding) {
516                    list = new StoredList(index, entityBinding, true);
517                } else {
518                    list = new StoredList(index, valueBinding, true);
519                }
520                fail();
521            } catch (IllegalArgumentException expected) {}
522        }
523
524        testCreation(map, maxKey);
525        testCreation((StoredContainer) map.values(), maxKey);
526        testCreation((StoredContainer) map.keySet(), maxKey);
527        testCreation((StoredContainer) map.entrySet(), maxKey);
528        if (list != null) {
529            testCreation(list, maxKey);
530        }
531        testMapCreation(map);
532        testAll();
533    }
534
535    void testAll()
536        throws Exception {
537
538        checkKeySetAndValueSet();
539        readAll();
540        updateAll();
541        readAll();
542        if (!map.areKeysRenumbered()) {
543            removeOdd();
544            readEven();
545            addOdd();
546            readAll();
547            removeOddIter();
548            readEven();
549            if (imap.areDuplicatesAllowed()) {
550                addOddDup();
551            } else {
552                addOdd();
553            }
554            readAll();
555            removeOddEntry();
556            readEven();
557            addOdd();
558            readAll();
559            if (isEntityBinding) {
560                removeOddEntity();
561                readEven();
562                addOddEntity();
563                readAll();
564            }
565            bulkOperations();
566        }
567        if (isListAddAllowed()) {
568            removeOddList();
569            readEvenList();
570            addOddList();
571            readAll();
572            if (!isEntityBinding) {
573                removeOddListValue();
574                readEvenList();
575                addOddList();
576                readAll();
577            }
578        }
579        if (list != null) {
580            bulkListOperations();
581        } else {
582            listOperationsNotAllowed();
583        }
584        if (smap != null) {
585            readWriteRange(SUB,  1, 1);
586            readWriteRange(HEAD, 1, 1);
587            readWriteRange(SUB,  1, maxKey);
588            readWriteRange(HEAD, 1, maxKey);
589            readWriteRange(TAIL, 1, maxKey);
590            readWriteRange(SUB,  1, 3);
591            readWriteRange(HEAD, 1, 3);
592            readWriteRange(SUB,  2, 2);
593            readWriteRange(SUB,  2, maxKey);
594            readWriteRange(TAIL, 2, maxKey);
595            readWriteRange(SUB,  maxKey, maxKey);
596            readWriteRange(TAIL, maxKey, maxKey);
597            readWriteRange(SUB,  maxKey + 1, maxKey + 1);
598            readWriteRange(TAIL, maxKey + 1, maxKey + 1);
599            readWriteRange(SUB,  0, 0);
600            readWriteRange(HEAD, 0, 0);
601        }
602        updateAll();
603        readAll();
604        if (map.areDuplicatesAllowed()) {
605            readWriteDuplicates();
606            readAll();
607        } else {
608            duplicatesNotAllowed();
609            readAll();
610        }
611        if (testEnv.isCdbMode()) {
612            testCdbLocking();
613        }
614        removeAll();
615        if (isListAddAllowed()) {
616            testIterAddList();
617            clearAll();
618        }
619        if (imap.areDuplicatesAllowed()) {
620            testIterAddDuplicates();
621            clearAll();
622        }
623        if (isListAddAllowed()) {
624            addAllList();
625            readAll();
626            removeAllList();
627        }
628        appendAll();
629    }
630
631    void checkKeySetAndValueSet() {
632
633        // use bulk operations to check that explicitly constructed
634        // keySet/valueSet are equivalent
635        assertEquals(keySet, imap.keySet());
636        if (valueSet != null) {
637            assertEquals(valueSet, imap.values());
638        }
639    }
640
641    Iterator iterator(Collection storedCollection) {
642
643        if (testStoredIterator) {
644            return ((StoredCollection) storedCollection).storedIterator();
645        } else {
646            return storedCollection.iterator();
647        }
648    }
649
650    void addAll()
651        throws Exception {
652
653        writeRunner.run(new TransactionWorker() {
654            public void doWork() throws Exception {
655                assertTrue(imap.isEmpty());
656                Iterator iter = iterator(imap.entrySet());
657                try {
658                    assertTrue(!iter.hasNext());
659                } finally {
660                    StoredIterator.close(iter);
661                }
662                assertEquals(0, imap.keySet().toArray().length);
663                assertEquals(0, imap.keySet().toArray(new Object[0]).length);
664                assertEquals(0, imap.entrySet().toArray().length);
665                assertEquals(0, imap.entrySet().toArray(new Object[0]).length);
666                assertEquals(0, imap.values().toArray().length);
667                assertEquals(0, imap.values().toArray(new Object[0]).length);
668
669                for (int i = beginKey; i <= endKey; i += 1) {
670                    Long key = makeKey(i);
671                    Object val = makeVal(i);
672                    assertNull(imap.get(key));
673                    assertTrue(!imap.keySet().contains(key));
674                    assertTrue(!imap.values().contains(val));
675                    assertNull(imap.put(key, val));
676                    assertEquals(val, imap.get(key));
677                    assertTrue(imap.keySet().contains(key));
678                    assertTrue(imap.values().contains(val));
679                    assertTrue(imap.duplicates(key).contains(val));
680                    if (!imap.areDuplicatesAllowed()) {
681                        assertEquals(val, imap.put(key, val));
682                    }
683                    checkDupsSize(1, imap.duplicates(key));
684                }
685                assertTrue(!imap.isEmpty());
686            }
687        });
688    }
689
690    void appendAll()
691        throws Exception {
692
693        writeRunner.run(new TransactionWorker() {
694            public void doWork() throws Exception {
695                assertTrue(imap.isEmpty());
696
697                TestKeyAssigner keyAssigner = testStore.getKeyAssigner();
698                if (keyAssigner != null) {
699                    keyAssigner.reset();
700                }
701
702                for (int i = beginKey; i <= endKey; i += 1) {
703                    boolean useList = (i & 1) == 0;
704                    Long key = makeKey(i);
705                    Object val = makeVal(i);
706                    assertNull(imap.get(key));
707                    if (keyAssigner != null) {
708                        if (useList && ilist != null) {
709                            assertEquals(i - 1, ilist.append(val));
710                        } else {
711                            assertEquals(key, imap.append(val));
712                        }
713                        assertEquals(val, imap.get(key));
714                    } else {
715                        Long recnoKey;
716                        if (useList && ilist != null) {
717                            recnoKey = new Long(ilist.append(val) + 1);
718                        } else {
719                            recnoKey = (Long) imap.append(val);
720                        }
721                        assertNotNull(recnoKey);
722                        Object recnoVal;
723                        if (isEntityBinding) {
724                            recnoVal = makeEntity(recnoKey.intValue(), i);
725                        } else {
726                            recnoVal = val;
727                        }
728                        assertEquals(recnoVal, imap.get(recnoKey));
729                    }
730                }
731            }
732        });
733    }
734
735    void updateAll()
736        throws Exception {
737
738        writeRunner.run(new TransactionWorker() {
739            public void doWork() throws Exception {
740                for (int i = beginKey; i <= endKey; i += 1) {
741                    Long key = makeKey(i);
742                    Object val = makeVal(i);
743                    if (!imap.areDuplicatesAllowed()) {
744                        assertEquals(val, imap.put(key, val));
745                    }
746                    if (isEntityBinding) {
747                        assertTrue(!imap.values().add(val));
748                    }
749                    checkDupsSize(1, imap.duplicates(key));
750                    if (ilist != null) {
751                        int idx = i - 1;
752                        assertEquals(val, ilist.set(idx, val));
753                    }
754                }
755                updateIter(map.entrySet());
756                updateIter(map.values());
757                if (beginKey <= endKey) {
758                    ListIterator iter = (ListIterator) iterator(map.keySet());
759                    try {
760                        assertNotNull(iter.next());
761                        iter.set(makeKey(beginKey));
762                        fail();
763                    } catch (UnsupportedOperationException e) {
764                    } finally {
765                        StoredIterator.close(iter);
766                    }
767                }
768                if (list != null) {
769                    updateIter(list);
770                }
771            }
772        });
773    }
774
775    void updateIter(final Collection coll)
776        throws Exception {
777
778        writeIterRunner.run(new TransactionWorker() {
779            public void doWork() throws Exception {
780                ListIterator iter = (ListIterator) iterator(coll);
781                try {
782                    for (int i = beginKey; i <= endKey; i += 1) {
783                        assertTrue(iter.hasNext());
784                        Object obj = iter.next();
785                        if (map.isOrdered()) {
786                            assertEquals(i, intIter(coll, obj));
787                        }
788                        if (index != null) {
789                            try {
790                                setValuePlusOne(iter, obj);
791                                fail();
792                            } catch (UnsupportedOperationException e) {}
793                        } else if
794                           (((StoredCollection) coll).areDuplicatesOrdered()) {
795                            try {
796                                setValuePlusOne(iter, obj);
797                                fail();
798                            } catch (RuntimeException e) {
799                                Exception e2 = ExceptionUnwrapper.unwrap(e);
800                                assertTrue(e2.getClass().getName(),
801                                      e2 instanceof IllegalArgumentException ||
802                                      e2 instanceof DatabaseException);
803                            }
804                        } else {
805                            setValuePlusOne(iter, obj);
806                            /* Ensure iterator position is correct. */
807                            if (map.isOrdered()) {
808                                assertTrue(iter.hasPrevious());
809                                obj = iter.previous();
810                                assertEquals(i, intIter(coll, obj));
811                                assertTrue(iter.hasNext());
812                                obj = iter.next();
813                                assertEquals(i, intIter(coll, obj));
814                            }
815                        }
816                    }
817                    assertTrue(!iter.hasNext());
818                } finally {
819                    StoredIterator.close(iter);
820                }
821            }
822        });
823    }
824
825    void setValuePlusOne(ListIterator iter, Object obj) {
826
827        if (obj instanceof Map.Entry) {
828            Map.Entry entry = (Map.Entry) obj;
829            Long key = (Long) entry.getKey();
830            Object oldVal = entry.getValue();
831            Object val = makeVal(key.intValue() + 1);
832            if (isEntityBinding) {
833                try {
834                    // must fail on attempt to change the key via an entity
835                    entry.setValue(val);
836                    fail();
837                } catch (IllegalArgumentException e) {}
838                val = makeEntity(key.intValue(), key.intValue() + 1);
839            }
840            entry.setValue(val);
841            assertEquals(val, entry.getValue());
842            assertEquals(val, map.get(key));
843            assertTrue(map.duplicates(key).contains(val));
844            checkDupsSize(1, map.duplicates(key));
845            entry.setValue(oldVal);
846            assertEquals(oldVal, entry.getValue());
847            assertEquals(oldVal, map.get(key));
848            assertTrue(map.duplicates(key).contains(oldVal));
849            checkDupsSize(1, map.duplicates(key));
850        } else {
851            Object oldVal = obj;
852            Long key = makeKey(intVal(obj));
853            Object val = makeVal(key.intValue() + 1);
854            if (isEntityBinding) {
855                try {
856                    // must fail on attempt to change the key via an entity
857                    iter.set(val);
858                    fail();
859                } catch (IllegalArgumentException e) {}
860                val = makeEntity(key.intValue(), key.intValue() + 1);
861            }
862            iter.set(val);
863            assertEquals(val, map.get(key));
864            assertTrue(map.duplicates(key).contains(val));
865            checkDupsSize(1, map.duplicates(key));
866            iter.set(oldVal);
867            assertEquals(oldVal, map.get(key));
868            assertTrue(map.duplicates(key).contains(oldVal));
869            checkDupsSize(1, map.duplicates(key));
870        }
871    }
872
873    void removeAll()
874        throws Exception {
875
876        writeIterRunner.run(new TransactionWorker() {
877            public void doWork() throws Exception {
878                assertTrue(!map.isEmpty());
879                ListIterator iter = null;
880                try {
881                    if (list != null) {
882                        iter = (ListIterator) iterator(list);
883                    } else {
884                        iter = (ListIterator) iterator(map.values());
885                    }
886                    iteratorSetAndRemoveNotAllowed(iter);
887
888                    Object val = iter.next();
889                    assertNotNull(val);
890                    iter.remove();
891                    iteratorSetAndRemoveNotAllowed(iter);
892
893                    if (index == null) {
894                        val = iter.next();
895                        assertNotNull(val);
896                        iter.set(val);
897
898                        if (map.areDuplicatesAllowed()) {
899                            iter.add(makeVal(intVal(val), intVal(val) + 1));
900                            iteratorSetAndRemoveNotAllowed(iter);
901                        }
902                    }
903                } finally {
904                    StoredIterator.close(iter);
905                }
906                map.clear();
907                assertTrue(map.isEmpty());
908                assertTrue(map.entrySet().isEmpty());
909                assertTrue(map.keySet().isEmpty());
910                assertTrue(map.values().isEmpty());
911                for (int i = beginKey; i <= endKey; i += 1) {
912                    Long key = makeKey(i);
913                    Object val = makeVal(i);
914                    assertNull(map.get(key));
915                    assertTrue(!map.duplicates(key).contains(val));
916                    checkDupsSize(0, map.duplicates(key));
917                }
918            }
919        });
920    }
921
922    void clearAll()
923        throws Exception {
924
925        writeRunner.run(new TransactionWorker() {
926            public void doWork() throws Exception {
927                map.clear();
928                assertTrue(map.isEmpty());
929            }
930        });
931    }
932
933    /**
934     * Tests that removing while iterating works properly, especially when
935     * removing everything in the key range or everything from some point to
936     * the end of the range. [#15858]
937     */
938    void removeIter()
939        throws Exception {
940
941        writeIterRunner.run(new TransactionWorker() {
942            public void doWork() throws Exception {
943                ListIterator iter;
944
945                /* Save contents. */
946                HashMap<Object,Object> savedMap =
947                    new HashMap<Object,Object>(map);
948                assertEquals(savedMap, map);
949
950                /* Remove all moving forward. */
951                iter = (ListIterator) iterator(map.keySet());
952                try {
953                    while (iter.hasNext()) {
954                        assertNotNull(iter.next());
955                        iter.remove();
956                    }
957                    assertTrue(!iter.hasNext());
958                    assertTrue(!iter.hasPrevious());
959                    assertTrue(map.isEmpty());
960                } finally {
961                    StoredIterator.close(iter);
962                }
963
964                /* Restore contents. */
965                imap.putAll(savedMap);
966                assertEquals(savedMap, map);
967
968                /* Remove all moving backward. */
969                iter = (ListIterator) iterator(map.keySet());
970                try {
971                    while (iter.hasNext()) {
972                        assertNotNull(iter.next());
973                    }
974                    while (iter.hasPrevious()) {
975                        assertNotNull(iter.previous());
976                        iter.remove();
977                    }
978                    assertTrue(!iter.hasNext());
979                    assertTrue(!iter.hasPrevious());
980                    assertTrue(map.isEmpty());
981                } finally {
982                    StoredIterator.close(iter);
983                }
984
985                /* Restore contents. */
986                imap.putAll(savedMap);
987                assertEquals(savedMap, map);
988
989                int first = Math.max(1, beginKey);
990                int last = Math.min(maxKey, endKey);
991
992                /* Skip N forward, remove all from that point forward. */
993                for (int readTo = first + 1; readTo <= last; readTo += 1) {
994                    iter = (ListIterator) iterator(map.keySet());
995                    try {
996                        for (int i = first; i < readTo; i += 1) {
997                            assertTrue(iter.hasNext());
998                            assertNotNull(iter.next());
999                        }
1000                        for (int i = readTo; i <= last; i += 1) {
1001                            assertTrue(iter.hasNext());
1002                            assertNotNull(iter.next());
1003                            iter.remove();
1004                        }
1005                        assertTrue(!iter.hasNext());
1006                        assertTrue(iter.hasPrevious());
1007                        assertEquals(readTo - first, map.size());
1008                    } finally {
1009                        StoredIterator.close(iter);
1010                    }
1011
1012                    /* Restore contents. */
1013                    for (Map.Entry entry : savedMap.entrySet()) {
1014                        if (!imap.entrySet().contains(entry)) {
1015                            imap.put(entry.getKey(), entry.getValue());
1016                        }
1017                    }
1018                    assertEquals(savedMap, map);
1019                }
1020
1021                /* Skip N backward, remove all from that point backward. */
1022                for (int readTo = last - 1; readTo >= first; readTo -= 1) {
1023                    iter = (ListIterator) iterator(map.keySet());
1024                    try {
1025                        while (iter.hasNext()) {
1026                            assertNotNull(iter.next());
1027                        }
1028                        for (int i = last; i > readTo; i -= 1) {
1029                            assertTrue(iter.hasPrevious());
1030                            assertNotNull(iter.previous());
1031                        }
1032                        for (int i = readTo; i >= first; i -= 1) {
1033                            assertTrue(iter.hasPrevious());
1034                            assertNotNull(iter.previous());
1035                            iter.remove();
1036                        }
1037                        assertTrue(!iter.hasPrevious());
1038                        assertTrue(iter.hasNext());
1039                        assertEquals(last - readTo, map.size());
1040                    } finally {
1041                        StoredIterator.close(iter);
1042                    }
1043
1044                    /* Restore contents. */
1045                    for (Map.Entry entry : savedMap.entrySet()) {
1046                        if (!imap.entrySet().contains(entry)) {
1047                            imap.put(entry.getKey(), entry.getValue());
1048                        }
1049                    }
1050                    assertEquals(savedMap, map);
1051                }
1052            }
1053        });
1054    }
1055
1056    void iteratorSetAndRemoveNotAllowed(ListIterator i) {
1057
1058        try {
1059            i.remove();
1060            fail();
1061        } catch (IllegalStateException e) {}
1062
1063        if (index == null) {
1064            try {
1065                Object val = makeVal(1);
1066                i.set(val);
1067                fail();
1068            } catch (IllegalStateException e) {}
1069        }
1070    }
1071
1072    void removeOdd()
1073        throws Exception {
1074
1075        writeRunner.run(new TransactionWorker() {
1076            public void doWork() throws Exception {
1077                boolean toggle = false;
1078                for (int i = beginKey; i <= endKey; i += 2) {
1079                    toggle = !toggle;
1080                    Long key = makeKey(i);
1081                    Object val = makeVal(i);
1082                    if (toggle) {
1083                        assertTrue(map.keySet().contains(key));
1084                        assertTrue(map.keySet().remove(key));
1085                        assertTrue(!map.keySet().contains(key));
1086                    } else {
1087                        assertTrue(map.containsValue(val));
1088                        Object oldVal = map.remove(key);
1089                        assertEquals(oldVal, val);
1090                        assertTrue(!map.containsKey(key));
1091                        assertTrue(!map.containsValue(val));
1092                    }
1093                    assertNull(map.get(key));
1094                    assertTrue(!map.duplicates(key).contains(val));
1095                    checkDupsSize(0, map.duplicates(key));
1096                }
1097            }
1098        });
1099    }
1100
1101    void removeOddEntity()
1102        throws Exception {
1103
1104        writeRunner.run(new TransactionWorker() {
1105            public void doWork() throws Exception {
1106                for (int i = beginKey; i <= endKey; i += 2) {
1107                    Long key = makeKey(i);
1108                    Object val = makeVal(i);
1109                    assertTrue(map.values().contains(val));
1110                    assertTrue(map.values().remove(val));
1111                    assertTrue(!map.values().contains(val));
1112                    assertNull(map.get(key));
1113                    assertTrue(!map.duplicates(key).contains(val));
1114                    checkDupsSize(0, map.duplicates(key));
1115                }
1116            }
1117        });
1118    }
1119
1120    void removeOddEntry()
1121        throws Exception {
1122
1123        writeRunner.run(new TransactionWorker() {
1124            public void doWork() throws Exception {
1125                for (int i = beginKey; i <= endKey; i += 2) {
1126                    Long key = makeKey(i);
1127                    Object val = mapEntry(i);
1128                    assertTrue(map.entrySet().contains(val));
1129                    assertTrue(map.entrySet().remove(val));
1130                    assertTrue(!map.entrySet().contains(val));
1131                    assertNull(map.get(key));
1132                }
1133            }
1134        });
1135    }
1136
1137    void removeOddIter()
1138        throws Exception {
1139
1140        writeIterRunner.run(new TransactionWorker() {
1141            public void doWork() throws Exception {
1142                Iterator iter = iterator(map.keySet());
1143                try {
1144                    for (int i = beginKey; i <= endKey; i += 1) {
1145                        assertTrue(iter.hasNext());
1146                        Long key = (Long) iter.next();
1147                        assertNotNull(key);
1148                        if (map instanceof SortedMap) {
1149                            assertEquals(makeKey(i), key);
1150                        }
1151                        if ((key.intValue() & 1) != 0) {
1152                            iter.remove();
1153                        }
1154                    }
1155                } finally {
1156                    StoredIterator.close(iter);
1157                }
1158            }
1159        });
1160    }
1161
1162    void removeOddList()
1163        throws Exception {
1164
1165        writeRunner.run(new TransactionWorker() {
1166            public void doWork() throws Exception {
1167                for (int i = beginKey; i <= endKey; i += 2) {
1168                    // remove by index
1169                    // (with entity binding, embbeded keys in values are
1170                    // being changed so we can't use values for comparison)
1171                    int idx = (i - beginKey) / 2;
1172                    Object val = makeVal(i);
1173                    if (!isEntityBinding) {
1174                        assertTrue(list.contains(val));
1175                        assertEquals(val, list.get(idx));
1176                        assertEquals(idx, list.indexOf(val));
1177                    }
1178                    assertNotNull(list.get(idx));
1179                    if (isEntityBinding) {
1180                        assertNotNull(list.remove(idx));
1181                    } else {
1182                        assertTrue(list.contains(val));
1183                        assertEquals(val, list.remove(idx));
1184                    }
1185                    assertTrue(!list.remove(val));
1186                    assertTrue(!list.contains(val));
1187                    assertTrue(!val.equals(list.get(idx)));
1188                }
1189            }
1190        });
1191    }
1192
1193    void removeOddListValue()
1194        throws Exception {
1195
1196        writeRunner.run(new TransactionWorker() {
1197            public void doWork() throws Exception {
1198                for (int i = beginKey; i <= endKey; i += 2) {
1199                    // for non-entity case remove by value
1200                    // (with entity binding, embbeded keys in values are
1201                    // being changed so we can't use values for comparison)
1202                    int idx = (i - beginKey) / 2;
1203                    Object val = makeVal(i);
1204                    assertTrue(list.contains(val));
1205                    assertEquals(val, list.get(idx));
1206                    assertEquals(idx, list.indexOf(val));
1207                    assertTrue(list.remove(val));
1208                    assertTrue(!list.remove(val));
1209                    assertTrue(!list.contains(val));
1210                    assertTrue(!val.equals(list.get(idx)));
1211                }
1212            }
1213        });
1214    }
1215
1216    void addOdd()
1217        throws Exception {
1218
1219        writeRunner.run(new TransactionWorker() {
1220            public void doWork() throws Exception {
1221                // add using Map.put()
1222                for (int i = beginKey; i <= endKey; i += 2) {
1223                    Long key = makeKey(i);
1224                    Object val = makeVal(i);
1225                    assertNull(imap.get(key));
1226                    assertNull(imap.put(key, val));
1227                    assertEquals(val, imap.get(key));
1228                    assertTrue(imap.duplicates(key).contains(val));
1229                    checkDupsSize(1, imap.duplicates(key));
1230                    if (isEntityBinding) {
1231                        assertTrue(!imap.values().add(val));
1232                    }
1233                    if (!imap.areDuplicatesAllowed()) {
1234                        assertEquals(val, imap.put(key, val));
1235                    }
1236                }
1237            }
1238        });
1239    }
1240
1241    void addOddEntity()
1242        throws Exception {
1243
1244        writeRunner.run(new TransactionWorker() {
1245            public void doWork() throws Exception {
1246                // add using Map.values().add()
1247                for (int i = beginKey; i <= endKey; i += 2) {
1248                    Long key = makeKey(i);
1249                    Object val = makeVal(i);
1250                    assertNull(imap.get(key));
1251                    assertTrue(!imap.values().contains(val));
1252                    assertTrue(imap.values().add(val));
1253                    assertEquals(val, imap.get(key));
1254                    assertTrue(imap.values().contains(val));
1255                    assertTrue(imap.duplicates(key).contains(val));
1256                    checkDupsSize(1, imap.duplicates(key));
1257                    if (isEntityBinding) {
1258                        assertTrue(!imap.values().add(val));
1259                    }
1260                }
1261            }
1262        });
1263    }
1264
1265    void addOddDup()
1266        throws Exception {
1267
1268        writeRunner.run(new TransactionWorker() {
1269            public void doWork() throws Exception {
1270                // add using Map.duplicates().add()
1271                for (int i = beginKey; i <= endKey; i += 2) {
1272                    Long key = makeKey(i);
1273                    Object val = makeVal(i);
1274                    assertNull(imap.get(key));
1275                    assertTrue(!imap.values().contains(val));
1276                    assertTrue(imap.duplicates(key).add(val));
1277                    assertEquals(val, imap.get(key));
1278                    assertTrue(imap.values().contains(val));
1279                    assertTrue(imap.duplicates(key).contains(val));
1280                    checkDupsSize(1, imap.duplicates(key));
1281                    assertTrue(!imap.duplicates(key).add(val));
1282                    if (isEntityBinding) {
1283                        assertTrue(!imap.values().add(val));
1284                    }
1285                }
1286            }
1287        });
1288    }
1289
1290    void addOddList()
1291        throws Exception {
1292
1293        writeRunner.run(new TransactionWorker() {
1294            public void doWork() throws Exception {
1295                for (int i = beginKey; i <= endKey; i += 2) {
1296                    int idx = i - beginKey;
1297                    Object val = makeVal(i);
1298                    assertTrue(!list.contains(val));
1299                    assertTrue(!val.equals(list.get(idx)));
1300                    list.add(idx, val);
1301                    assertTrue(list.contains(val));
1302                    assertEquals(val, list.get(idx));
1303                }
1304            }
1305        });
1306    }
1307
1308    void addAllList()
1309        throws Exception {
1310
1311        writeRunner.run(new TransactionWorker() {
1312            public void doWork() throws Exception {
1313                for (int i = beginKey; i <= endKey; i += 1) {
1314                    int idx = i - beginKey;
1315                    Object val = makeVal(i);
1316                    assertTrue(!list.contains(val));
1317                    assertTrue(list.add(val));
1318                    assertTrue(list.contains(val));
1319                    assertEquals(val, list.get(idx));
1320                }
1321            }
1322        });
1323    }
1324
1325    void removeAllList()
1326        throws Exception {
1327
1328        writeRunner.run(new TransactionWorker() {
1329            public void doWork() throws Exception {
1330                assertTrue(!list.isEmpty());
1331                list.clear();
1332                assertTrue(list.isEmpty());
1333                for (int i = beginKey; i <= endKey; i += 1) {
1334                    int idx = i - beginKey;
1335                    assertNull(list.get(idx));
1336                }
1337            }
1338        });
1339    }
1340
1341    void testIterAddList()
1342        throws Exception {
1343
1344        writeIterRunner.run(new TransactionWorker() {
1345            public void doWork() throws Exception {
1346                ListIterator i = (ListIterator) iterator(list);
1347                try {
1348                    assertTrue(!i.hasNext());
1349                    i.add(makeVal(3));
1350                    assertTrue(!i.hasNext());
1351                    assertTrue(i.hasPrevious());
1352                    assertEquals(3, intVal(i.previous()));
1353
1354                    i.add(makeVal(1));
1355                    assertTrue(i.hasPrevious());
1356                    assertTrue(i.hasNext());
1357                    assertEquals(1, intVal(i.previous()));
1358                    assertTrue(i.hasNext());
1359                    assertEquals(1, intVal(i.next()));
1360                    assertTrue(i.hasNext());
1361                    assertEquals(3, intVal(i.next()));
1362                    assertEquals(3, intVal(i.previous()));
1363
1364                    assertTrue(i.hasNext());
1365                    i.add(makeVal(2));
1366                    assertTrue(i.hasNext());
1367                    assertTrue(i.hasPrevious());
1368                    assertEquals(2, intVal(i.previous()));
1369                    assertTrue(i.hasNext());
1370                    assertEquals(2, intVal(i.next()));
1371                    assertTrue(i.hasNext());
1372                    assertEquals(3, intVal(i.next()));
1373
1374                    assertTrue(!i.hasNext());
1375                    i.add(makeVal(4));
1376                    i.add(makeVal(5));
1377                    assertTrue(!i.hasNext());
1378                    assertEquals(5, intVal(i.previous()));
1379                    assertEquals(4, intVal(i.previous()));
1380                    assertEquals(3, intVal(i.previous()));
1381                    assertEquals(2, intVal(i.previous()));
1382                    assertEquals(1, intVal(i.previous()));
1383                    assertTrue(!i.hasPrevious());
1384                } finally {
1385                    StoredIterator.close(i);
1386                }
1387            }
1388        });
1389    }
1390
1391    void testIterAddDuplicates()
1392        throws Exception {
1393
1394        writeIterRunner.run(new TransactionWorker() {
1395            public void doWork() throws Exception {
1396                assertNull(imap.put(makeKey(1), makeVal(1)));
1397                ListIterator i =
1398                    (ListIterator) iterator(imap.duplicates(makeKey(1)));
1399                try {
1400                    if (imap.areDuplicatesOrdered()) {
1401                        i.add(makeVal(1, 4));
1402                        i.add(makeVal(1, 2));
1403                        i.add(makeVal(1, 3));
1404                        while (i.hasPrevious()) i.previous();
1405                        assertEquals(1, intVal(i.next()));
1406                        assertEquals(2, intVal(i.next()));
1407                        assertEquals(3, intVal(i.next()));
1408                        assertEquals(4, intVal(i.next()));
1409                        assertTrue(!i.hasNext());
1410                    } else {
1411                        assertEquals(1, intVal(i.next()));
1412                        i.add(makeVal(1, 2));
1413                        i.add(makeVal(1, 3));
1414                        assertTrue(!i.hasNext());
1415                        assertTrue(i.hasPrevious());
1416                        assertEquals(3, intVal(i.previous()));
1417                        assertEquals(2, intVal(i.previous()));
1418                        assertEquals(1, intVal(i.previous()));
1419                        assertTrue(!i.hasPrevious());
1420                        i.add(makeVal(1, 4));
1421                        i.add(makeVal(1, 5));
1422                        assertTrue(i.hasNext());
1423                        assertEquals(5, intVal(i.previous()));
1424                        assertEquals(4, intVal(i.previous()));
1425                        assertTrue(!i.hasPrevious());
1426                        assertEquals(4, intVal(i.next()));
1427                        assertEquals(5, intVal(i.next()));
1428                        assertEquals(1, intVal(i.next()));
1429                        assertEquals(2, intVal(i.next()));
1430                        assertEquals(3, intVal(i.next()));
1431                        assertTrue(!i.hasNext());
1432                    }
1433                } finally {
1434                    StoredIterator.close(i);
1435                }
1436            }
1437        });
1438    }
1439
1440    void readAll()
1441        throws Exception {
1442
1443        readRunner.run(new TransactionWorker() {
1444            public void doWork() throws Exception {
1445                // map
1446
1447                assertNotNull(map.toString());
1448                for (int i = beginKey; i <= endKey; i += 1) {
1449                    Long key = makeKey(i);
1450                    Object val = map.get(key);
1451                    assertEquals(makeVal(i), val);
1452                    assertTrue(map.containsKey(key));
1453                    assertTrue(map.containsValue(val));
1454                    assertTrue(map.keySet().contains(key));
1455                    assertTrue(map.values().contains(val));
1456                    assertTrue(map.duplicates(key).contains(val));
1457                    checkDupsSize(1, map.duplicates(key));
1458                }
1459                assertNull(map.get(makeKey(-1)));
1460                assertNull(map.get(makeKey(0)));
1461                assertNull(map.get(makeKey(beginKey - 1)));
1462                assertNull(map.get(makeKey(endKey + 1)));
1463                checkDupsSize(0, map.duplicates(makeKey(-1)));
1464                checkDupsSize(0, map.duplicates(makeKey(0)));
1465                checkDupsSize(0, map.duplicates(makeKey(beginKey - 1)));
1466                checkDupsSize(0, map.duplicates(makeKey(endKey + 1)));
1467
1468                // entrySet
1469
1470                Set set = map.entrySet();
1471                assertNotNull(set.toString());
1472                assertEquals(beginKey > endKey, set.isEmpty());
1473                Iterator iter = iterator(set);
1474                try {
1475                    for (int i = beginKey; i <= endKey; i += 1) {
1476                        assertTrue(iter.hasNext());
1477                        Map.Entry entry = (Map.Entry) iter.next();
1478                        Long key = (Long) entry.getKey();
1479                        Object val = entry.getValue();
1480                        if (map instanceof SortedMap) {
1481                            assertEquals(intKey(key), i);
1482                        }
1483                        assertEquals(intKey(key), intVal(val));
1484                        assertTrue(set.contains(entry));
1485                    }
1486                    assertTrue(!iter.hasNext());
1487                } finally {
1488                    StoredIterator.close(iter);
1489                }
1490                Map.Entry[] entries =
1491                    (Map.Entry[]) set.toArray(new Map.Entry[0]);
1492                assertNotNull(entries);
1493                assertEquals(endKey - beginKey + 1, entries.length);
1494                for (int i = beginKey; i <= endKey; i += 1) {
1495                    Map.Entry entry = entries[i - beginKey];
1496                    assertNotNull(entry);
1497                    if (map instanceof SortedMap) {
1498                        assertEquals(makeKey(i), entry.getKey());
1499                        assertEquals(makeVal(i), entry.getValue());
1500                    }
1501                }
1502                readIterator(set, iterator(set), beginKey, endKey);
1503                if (smap != null) {
1504                    SortedSet sset = (SortedSet) set;
1505                    if (beginKey == 1 && endKey >= 1) {
1506                        readIterator(sset,
1507                                     iterator(sset.subSet(mapEntry(1),
1508                                                          mapEntry(2))),
1509                                     1, 1);
1510                    }
1511                    if (beginKey <= 2 && endKey >= 2) {
1512                        readIterator(sset,
1513                                     iterator(sset.subSet(mapEntry(2),
1514                                                          mapEntry(3))),
1515                                     2, 2);
1516                    }
1517                    if (beginKey <= endKey) {
1518                        readIterator(sset,
1519                                     iterator(sset.subSet
1520                                                (mapEntry(endKey),
1521                                                 mapEntry(endKey + 1))),
1522                                     endKey, endKey);
1523                    }
1524                    if (isSubMap()) {
1525                        if (beginKey <= endKey) {
1526                            if (rangeType != TAIL) {
1527                                try {
1528                                    sset.subSet(mapEntry(endKey + 1),
1529                                                mapEntry(endKey + 2));
1530                                    fail();
1531                                } catch (IllegalArgumentException e) {}
1532                            }
1533                            if (rangeType != HEAD) {
1534                                try {
1535                                    sset.subSet(mapEntry(0),
1536                                                mapEntry(1));
1537                                    fail();
1538                                } catch (IllegalArgumentException e) {}
1539                            }
1540                        }
1541                    } else {
1542                        readIterator(sset,
1543                                     iterator(sset.subSet
1544                                                (mapEntry(endKey + 1),
1545                                                 mapEntry(endKey + 2))),
1546                                     endKey, endKey - 1);
1547                        readIterator(sset,
1548                                     iterator(sset.subSet(mapEntry(0),
1549                                                          mapEntry(1))),
1550                                     0, -1);
1551                    }
1552                }
1553
1554                // keySet
1555
1556                set = map.keySet();
1557                assertNotNull(set.toString());
1558                assertEquals(beginKey > endKey, set.isEmpty());
1559                iter = iterator(set);
1560                try {
1561                    for (int i = beginKey; i <= endKey; i += 1) {
1562                        assertTrue(iter.hasNext());
1563                        Long key = (Long) iter.next();
1564                        assertTrue(set.contains(key));
1565                        Object val = map.get(key);
1566                        if (map instanceof SortedMap) {
1567                            assertEquals(key, makeKey(i));
1568                        }
1569                        assertEquals(intKey(key), intVal(val));
1570                    }
1571                    assertTrue("" + beginKey + ' ' + endKey, !iter.hasNext());
1572                } finally {
1573                    StoredIterator.close(iter);
1574                }
1575                Long[] keys = (Long[]) set.toArray(new Long[0]);
1576                assertNotNull(keys);
1577                assertEquals(endKey - beginKey + 1, keys.length);
1578                for (int i = beginKey; i <= endKey; i += 1) {
1579                    Long key = keys[i - beginKey];
1580                    assertNotNull(key);
1581                    if (map instanceof SortedMap) {
1582                        assertEquals(makeKey(i), key);
1583                    }
1584                }
1585                readIterator(set, iterator(set), beginKey, endKey);
1586
1587                // values
1588
1589                Collection coll = map.values();
1590                assertNotNull(coll.toString());
1591                assertEquals(beginKey > endKey, coll.isEmpty());
1592                iter = iterator(coll);
1593                try {
1594                    for (int i = beginKey; i <= endKey; i += 1) {
1595                        assertTrue(iter.hasNext());
1596                        Object val = iter.next();
1597                        if (map instanceof SortedMap) {
1598                            assertEquals(makeVal(i), val);
1599                        }
1600                    }
1601                    assertTrue(!iter.hasNext());
1602                } finally {
1603                    StoredIterator.close(iter);
1604                }
1605                Object[] values = coll.toArray();
1606                assertNotNull(values);
1607                assertEquals(endKey - beginKey + 1, values.length);
1608                for (int i = beginKey; i <= endKey; i += 1) {
1609                    Object val = values[i - beginKey];
1610                    assertNotNull(val);
1611                    if (map instanceof SortedMap) {
1612                        assertEquals(makeVal(i), val);
1613                    }
1614                }
1615                readIterator(coll, iterator(coll), beginKey, endKey);
1616
1617                // list
1618
1619                if (list != null) {
1620                    assertNotNull(list.toString());
1621                    assertEquals(beginKey > endKey, list.isEmpty());
1622                    for (int i = beginKey; i <= endKey; i += 1) {
1623                        int idx = i - beginKey;
1624                        Object val = list.get(idx);
1625                        assertEquals(makeVal(i), val);
1626                        assertTrue(list.contains(val));
1627                        assertEquals(idx, list.indexOf(val));
1628                        assertEquals(idx, list.lastIndexOf(val));
1629                    }
1630                    ListIterator li = (ListIterator) iterator(list);
1631                    try {
1632                        for (int i = beginKey; i <= endKey; i += 1) {
1633                            int idx = i - beginKey;
1634                            assertTrue(li.hasNext());
1635                            assertEquals(idx, li.nextIndex());
1636                            Object val = li.next();
1637                            assertEquals(makeVal(i), val);
1638                            assertEquals(idx, li.previousIndex());
1639                        }
1640                        assertTrue(!li.hasNext());
1641                    } finally {
1642                        StoredIterator.close(li);
1643                    }
1644                    if (beginKey < endKey) {
1645                        li = list.listIterator(1);
1646                        try {
1647                            for (int i = beginKey + 1; i <= endKey; i += 1) {
1648                                int idx = i - beginKey;
1649                                assertTrue(li.hasNext());
1650                                assertEquals(idx, li.nextIndex());
1651                                Object val = li.next();
1652                                assertEquals(makeVal(i), val);
1653                                assertEquals(idx, li.previousIndex());
1654                            }
1655                            assertTrue(!li.hasNext());
1656                        } finally {
1657                            StoredIterator.close(li);
1658                        }
1659                    }
1660                    values = list.toArray();
1661                    assertNotNull(values);
1662                    assertEquals(endKey - beginKey + 1, values.length);
1663                    for (int i = beginKey; i <= endKey; i += 1) {
1664                        Object val = values[i - beginKey];
1665                        assertNotNull(val);
1666                        assertEquals(makeVal(i), val);
1667                    }
1668                    readIterator(list, iterator(list), beginKey, endKey);
1669                }
1670
1671                // first/last
1672
1673                if (smap != null) {
1674                    if (beginKey <= endKey &&
1675                        beginKey >= 1 && beginKey <= maxKey) {
1676                        assertEquals(makeKey(beginKey),
1677                                     smap.firstKey());
1678                        assertEquals(makeKey(beginKey),
1679                                     ((SortedSet) smap.keySet()).first());
1680                        Object entry = ((SortedSet) smap.entrySet()).first();
1681                        assertEquals(makeKey(beginKey),
1682                                     ((Map.Entry) entry).getKey());
1683                        if (smap.values() instanceof SortedSet) {
1684                            assertEquals(makeVal(beginKey),
1685                                         ((SortedSet) smap.values()).first());
1686                        }
1687                    } else {
1688                        assertNull(smap.firstKey());
1689                        assertNull(((SortedSet) smap.keySet()).first());
1690                        assertNull(((SortedSet) smap.entrySet()).first());
1691                        if (smap.values() instanceof SortedSet) {
1692                            assertNull(((SortedSet) smap.values()).first());
1693                        }
1694                    }
1695                    if (beginKey <= endKey &&
1696                        endKey >= 1 && endKey <= maxKey) {
1697                        assertEquals(makeKey(endKey),
1698                                     smap.lastKey());
1699                        assertEquals(makeKey(endKey),
1700                                     ((SortedSet) smap.keySet()).last());
1701                        Object entry = ((SortedSet) smap.entrySet()).last();
1702                        assertEquals(makeKey(endKey),
1703                                     ((Map.Entry) entry).getKey());
1704                        if (smap.values() instanceof SortedSet) {
1705                            assertEquals(makeVal(endKey),
1706                                         ((SortedSet) smap.values()).last());
1707                        }
1708                    } else {
1709                        assertNull(smap.lastKey());
1710                        assertNull(((SortedSet) smap.keySet()).last());
1711                        assertNull(((SortedSet) smap.entrySet()).last());
1712                        if (smap.values() instanceof SortedSet) {
1713                            assertNull(((SortedSet) smap.values()).last());
1714                        }
1715                    }
1716                }
1717            }
1718        });
1719    }
1720
1721    void readEven()
1722        throws Exception {
1723
1724        readRunner.run(new TransactionWorker() {
1725            public void doWork() throws Exception {
1726                int readBegin = ((beginKey & 1) != 0) ?
1727                                    (beginKey + 1) : beginKey;
1728                int readEnd = ((endKey & 1) != 0) ?  (endKey - 1) : endKey;
1729                int readIncr = 2;
1730
1731                // map
1732
1733                for (int i = beginKey; i <= endKey; i += 1) {
1734                    Long key = makeKey(i);
1735                    if ((i & 1) == 0) {
1736                        Object val = map.get(key);
1737                        assertEquals(makeVal(i), val);
1738                        assertTrue(map.containsKey(key));
1739                        assertTrue(map.containsValue(val));
1740                        assertTrue(map.keySet().contains(key));
1741                        assertTrue(map.values().contains(val));
1742                        assertTrue(map.duplicates(key).contains(val));
1743                        checkDupsSize(1, map.duplicates(key));
1744                    } else {
1745                        Object val = makeVal(i);
1746                        assertTrue(!map.containsKey(key));
1747                        assertTrue(!map.containsValue(val));
1748                        assertTrue(!map.keySet().contains(key));
1749                        assertTrue(!map.values().contains(val));
1750                        assertTrue(!map.duplicates(key).contains(val));
1751                        checkDupsSize(0, map.duplicates(key));
1752                    }
1753                }
1754
1755                // entrySet
1756
1757                Set set = map.entrySet();
1758                assertEquals(beginKey > endKey, set.isEmpty());
1759                Iterator iter = iterator(set);
1760                try {
1761                    for (int i = readBegin; i <= readEnd; i += readIncr) {
1762                        assertTrue(iter.hasNext());
1763                        Map.Entry entry = (Map.Entry) iter.next();
1764                        Long key = (Long) entry.getKey();
1765                        Object val = entry.getValue();
1766                        if (map instanceof SortedMap) {
1767                            assertEquals(intKey(key), i);
1768                        }
1769                        assertEquals(intKey(key), intVal(val));
1770                        assertTrue(set.contains(entry));
1771                    }
1772                    assertTrue(!iter.hasNext());
1773                } finally {
1774                    StoredIterator.close(iter);
1775                }
1776
1777                // keySet
1778
1779                set = map.keySet();
1780                assertEquals(beginKey > endKey, set.isEmpty());
1781                iter = iterator(set);
1782                try {
1783                    for (int i = readBegin; i <= readEnd; i += readIncr) {
1784                        assertTrue(iter.hasNext());
1785                        Long key = (Long) iter.next();
1786                        assertTrue(set.contains(key));
1787                        Object val = map.get(key);
1788                        if (map instanceof SortedMap) {
1789                            assertEquals(key, makeKey(i));
1790                        }
1791                        assertEquals(intKey(key), intVal(val));
1792                    }
1793                    assertTrue(!iter.hasNext());
1794                } finally {
1795                    StoredIterator.close(iter);
1796                }
1797
1798                // values
1799
1800                Collection coll = map.values();
1801                assertEquals(beginKey > endKey, coll.isEmpty());
1802                iter = iterator(coll);
1803                try {
1804                    for (int i = readBegin; i <= readEnd; i += readIncr) {
1805                        assertTrue(iter.hasNext());
1806                        Object val = iter.next();
1807                        if (map instanceof SortedMap) {
1808                            assertEquals(makeVal(i), val);
1809                        }
1810                    }
1811                    assertTrue(!iter.hasNext());
1812                } finally {
1813                    StoredIterator.close(iter);
1814                }
1815
1816
1817                // list not used since keys may not be renumbered for this
1818                // method to work in general
1819
1820                // first/last
1821
1822                if (smap != null) {
1823                    if (readBegin <= readEnd &&
1824                        readBegin >= 1 && readBegin <= maxKey) {
1825                        assertEquals(makeKey(readBegin),
1826                                     smap.firstKey());
1827                        assertEquals(makeKey(readBegin),
1828                                     ((SortedSet) smap.keySet()).first());
1829                        Object entry = ((SortedSet) smap.entrySet()).first();
1830                        assertEquals(makeKey(readBegin),
1831                                     ((Map.Entry) entry).getKey());
1832                        if (smap.values() instanceof SortedSet) {
1833                            assertEquals(makeVal(readBegin),
1834                                         ((SortedSet) smap.values()).first());
1835                        }
1836                    } else {
1837                        assertNull(smap.firstKey());
1838                        assertNull(((SortedSet) smap.keySet()).first());
1839                        assertNull(((SortedSet) smap.entrySet()).first());
1840                        if (smap.values() instanceof SortedSet) {
1841                            assertNull(((SortedSet) smap.values()).first());
1842                        }
1843                    }
1844                    if (readBegin <= readEnd &&
1845                        readEnd >= 1 && readEnd <= maxKey) {
1846                        assertEquals(makeKey(readEnd),
1847                                     smap.lastKey());
1848                        assertEquals(makeKey(readEnd),
1849                                     ((SortedSet) smap.keySet()).last());
1850                        Object entry = ((SortedSet) smap.entrySet()).last();
1851                        assertEquals(makeKey(readEnd),
1852                                     ((Map.Entry) entry).getKey());
1853                        if (smap.values() instanceof SortedSet) {
1854                            assertEquals(makeVal(readEnd),
1855                                         ((SortedSet) smap.values()).last());
1856                        }
1857                    } else {
1858                        assertNull(smap.lastKey());
1859                        assertNull(((SortedSet) smap.keySet()).last());
1860                        assertNull(((SortedSet) smap.entrySet()).last());
1861                        if (smap.values() instanceof SortedSet) {
1862                            assertNull(((SortedSet) smap.values()).last());
1863                        }
1864                    }
1865                }
1866            }
1867        });
1868    }
1869
1870    void readEvenList()
1871        throws Exception {
1872
1873        readRunner.run(new TransactionWorker() {
1874            public void doWork() throws Exception {
1875                int readBegin = ((beginKey & 1) != 0) ?
1876                                    (beginKey + 1) : beginKey;
1877                int readEnd = ((endKey & 1) != 0) ?  (endKey - 1) : endKey;
1878                int readIncr = 2;
1879
1880                assertEquals(beginKey > endKey, list.isEmpty());
1881                ListIterator iter = (ListIterator) iterator(list);
1882                try {
1883                    int idx = 0;
1884                    for (int i = readBegin; i <= readEnd; i += readIncr) {
1885                        assertTrue(iter.hasNext());
1886                        assertEquals(idx, iter.nextIndex());
1887                        Object val = iter.next();
1888                        assertEquals(idx, iter.previousIndex());
1889                        if (isEntityBinding) {
1890                            assertEquals(i, intVal(val));
1891                        } else {
1892                            assertEquals(makeVal(i), val);
1893                        }
1894                        idx += 1;
1895                    }
1896                    assertTrue(!iter.hasNext());
1897                } finally {
1898                    StoredIterator.close(iter);
1899                }
1900            }
1901        });
1902    }
1903
1904    void readIterator(Collection coll, Iterator iter,
1905                      int beginValue, int endValue) {
1906
1907        ListIterator li = (ListIterator) iter;
1908        boolean isList = (coll instanceof List);
1909        Iterator clone = null;
1910        try {
1911            // at beginning
1912            assertTrue(!li.hasPrevious());
1913            assertTrue(!li.hasPrevious());
1914            try { li.previous(); } catch (NoSuchElementException e) {}
1915            if (isList) {
1916                assertEquals(-1, li.previousIndex());
1917            }
1918            if (endValue < beginValue) {
1919                // is empty
1920                assertTrue(!iter.hasNext());
1921                try { iter.next(); } catch (NoSuchElementException e) {}
1922                if (isList) {
1923                    assertEquals(Integer.MAX_VALUE, li.nextIndex());
1924                }
1925            }
1926            // loop thru all and collect in array
1927            int[] values = new int[endValue - beginValue + 1];
1928            for (int i = beginValue; i <= endValue; i += 1) {
1929                assertTrue(iter.hasNext());
1930                int idx = i - beginKey;
1931                if (isList) {
1932                    assertEquals(idx, li.nextIndex());
1933                }
1934                int value = intIter(coll, iter.next());
1935                if (isList) {
1936                    assertEquals(idx, li.previousIndex());
1937                }
1938                values[i - beginValue] = value;
1939                if (((StoredCollection) coll).isOrdered()) {
1940                    assertEquals(i, value);
1941                } else {
1942                    assertTrue(value >= beginValue);
1943                    assertTrue(value <= endValue);
1944                }
1945            }
1946            // at end
1947            assertTrue(!iter.hasNext());
1948            try { iter.next(); } catch (NoSuchElementException e) {}
1949            if (isList) {
1950                assertEquals(Integer.MAX_VALUE, li.nextIndex());
1951            }
1952            // clone at same position
1953            clone = StoredCollections.iterator(iter);
1954            assertTrue(!clone.hasNext());
1955            // loop thru in reverse
1956            for (int i = endValue; i >= beginValue; i -= 1) {
1957                assertTrue(li.hasPrevious());
1958                int idx = i - beginKey;
1959                if (isList) {
1960                    assertEquals(idx, li.previousIndex());
1961                }
1962                int value = intIter(coll, li.previous());
1963                if (isList) {
1964                    assertEquals(idx, li.nextIndex());
1965                }
1966                assertEquals(values[i - beginValue], value);
1967            }
1968            // clone should not have changed
1969            assertTrue(!clone.hasNext());
1970            // at beginning
1971            assertTrue(!li.hasPrevious());
1972            try { li.previous(); } catch (NoSuchElementException e) {}
1973            if (isList) {
1974                assertEquals(-1, li.previousIndex());
1975            }
1976            // loop thru with some back-and-forth
1977            for (int i = beginValue; i <= endValue; i += 1) {
1978                assertTrue(iter.hasNext());
1979                int idx = i - beginKey;
1980                if (isList) {
1981                    assertEquals(idx, li.nextIndex());
1982                }
1983                Object obj = iter.next();
1984                if (isList) {
1985                    assertEquals(idx, li.previousIndex());
1986                }
1987                assertEquals(obj, li.previous());
1988                if (isList) {
1989                    assertEquals(idx, li.nextIndex());
1990                }
1991                assertEquals(obj, iter.next());
1992                if (isList) {
1993                    assertEquals(idx, li.previousIndex());
1994                }
1995                int value = intIter(coll, obj);
1996                assertEquals(values[i - beginValue], value);
1997            }
1998            // at end
1999            assertTrue(!iter.hasNext());
2000            try { iter.next(); } catch (NoSuchElementException e) {}
2001            if (isList) {
2002                assertEquals(Integer.MAX_VALUE, li.nextIndex());
2003            }
2004        } finally {
2005            StoredIterator.close(iter);
2006            StoredIterator.close(clone);
2007        }
2008    }
2009
2010    void bulkOperations()
2011        throws Exception {
2012
2013        writeRunner.run(new TransactionWorker() {
2014            public void doWork() throws Exception {
2015                HashMap hmap = new HashMap();
2016                for (int i = Math.max(1, beginKey);
2017                         i <= Math.min(maxKey, endKey);
2018                         i += 1) {
2019                    hmap.put(makeKey(i), makeVal(i));
2020                }
2021                assertEquals(hmap, map);
2022                assertEquals(hmap.entrySet(), map.entrySet());
2023                assertEquals(hmap.keySet(), map.keySet());
2024                assertEquals(map.values(), hmap.values());
2025
2026                assertTrue(map.entrySet().containsAll(hmap.entrySet()));
2027                assertTrue(map.keySet().containsAll(hmap.keySet()));
2028                assertTrue(map.values().containsAll(hmap.values()));
2029
2030                map.clear();
2031                assertTrue(map.isEmpty());
2032                imap.putAll(hmap);
2033                assertEquals(hmap, map);
2034
2035                assertTrue(map.entrySet().removeAll(hmap.entrySet()));
2036                assertTrue(map.entrySet().isEmpty());
2037                assertTrue(!map.entrySet().removeAll(hmap.entrySet()));
2038                assertTrue(imap.entrySet().addAll(hmap.entrySet()));
2039                assertTrue(map.entrySet().containsAll(hmap.entrySet()));
2040                assertTrue(!imap.entrySet().addAll(hmap.entrySet()));
2041                assertEquals(hmap, map);
2042
2043                assertTrue(!map.entrySet().retainAll(hmap.entrySet()));
2044                assertEquals(hmap, map);
2045                assertTrue(map.entrySet().retainAll(Collections.EMPTY_SET));
2046                assertTrue(map.isEmpty());
2047                imap.putAll(hmap);
2048                assertEquals(hmap, map);
2049
2050                assertTrue(map.values().removeAll(hmap.values()));
2051                assertTrue(map.values().isEmpty());
2052                assertTrue(!map.values().removeAll(hmap.values()));
2053                if (isEntityBinding) {
2054                    assertTrue(imap.values().addAll(hmap.values()));
2055                    assertTrue(map.values().containsAll(hmap.values()));
2056                    assertTrue(!imap.values().addAll(hmap.values()));
2057                } else {
2058                    imap.putAll(hmap);
2059                }
2060                assertEquals(hmap, map);
2061
2062                assertTrue(!map.values().retainAll(hmap.values()));
2063                assertEquals(hmap, map);
2064                assertTrue(map.values().retainAll(Collections.EMPTY_SET));
2065                assertTrue(map.isEmpty());
2066                imap.putAll(hmap);
2067                assertEquals(hmap, map);
2068
2069                assertTrue(map.keySet().removeAll(hmap.keySet()));
2070                assertTrue(map.keySet().isEmpty());
2071                assertTrue(!map.keySet().removeAll(hmap.keySet()));
2072                assertTrue(imap.keySet().addAll(hmap.keySet()));
2073                assertTrue(imap.keySet().containsAll(hmap.keySet()));
2074                if (index != null) {
2075                    assertTrue(map.keySet().isEmpty());
2076                }
2077                assertTrue(!imap.keySet().addAll(hmap.keySet()));
2078                // restore values to non-null
2079                imap.keySet().removeAll(hmap.keySet());
2080                imap.putAll(hmap);
2081                assertEquals(hmap, map);
2082
2083                assertTrue(!map.keySet().retainAll(hmap.keySet()));
2084                assertEquals(hmap, map);
2085                assertTrue(map.keySet().retainAll(Collections.EMPTY_SET));
2086                assertTrue(map.isEmpty());
2087                imap.putAll(hmap);
2088                assertEquals(hmap, map);
2089            }
2090        });
2091    }
2092
2093    void bulkListOperations()
2094        throws Exception {
2095
2096        writeRunner.run(new TransactionWorker() {
2097            public void doWork() throws Exception {
2098                ArrayList alist = new ArrayList();
2099                for (int i = beginKey; i <= endKey; i += 1) {
2100                    alist.add(makeVal(i));
2101                }
2102
2103                assertEquals(alist, list);
2104                assertTrue(list.containsAll(alist));
2105
2106                if (isListAddAllowed()) {
2107                    list.clear();
2108                    assertTrue(list.isEmpty());
2109                    assertTrue(ilist.addAll(alist));
2110                    assertEquals(alist, list);
2111                }
2112
2113                assertTrue(!list.retainAll(alist));
2114                assertEquals(alist, list);
2115
2116                if (isListAddAllowed()) {
2117                    assertTrue(list.retainAll(Collections.EMPTY_SET));
2118                    assertTrue(list.isEmpty());
2119                    assertTrue(ilist.addAll(alist));
2120                    assertEquals(alist, list);
2121                }
2122
2123                if (isListAddAllowed() && !isEntityBinding) {
2124                    // deleting in a renumbered list with entity binding will
2125                    // change the values dynamically, making it very difficult
2126                    // to test
2127                    assertTrue(list.removeAll(alist));
2128                    assertTrue(list.isEmpty());
2129                    assertTrue(!list.removeAll(alist));
2130                    assertTrue(ilist.addAll(alist));
2131                    assertTrue(list.containsAll(alist));
2132                    assertEquals(alist, list);
2133                }
2134
2135                if (isListAddAllowed() && !isEntityBinding) {
2136                    // addAll at an index is also very difficult to test with
2137                    // an entity binding
2138
2139                    // addAll at first index
2140                    ilist.addAll(beginKey, alist);
2141                    assertTrue(list.containsAll(alist));
2142                    assertEquals(2 * alist.size(), countElements(list));
2143                    for (int i = beginKey; i <= endKey; i += 1)
2144                        ilist.remove(beginKey);
2145                    assertEquals(alist, list);
2146
2147                    // addAll at last index
2148                    ilist.addAll(endKey, alist);
2149                    assertTrue(list.containsAll(alist));
2150                    assertEquals(2 * alist.size(), countElements(list));
2151                    for (int i = beginKey; i <= endKey; i += 1)
2152                        ilist.remove(endKey);
2153                    assertEquals(alist, list);
2154
2155                    // addAll in the middle
2156                    ilist.addAll(endKey - 1, alist);
2157                    assertTrue(list.containsAll(alist));
2158                    assertEquals(2 * alist.size(), countElements(list));
2159                    for (int i = beginKey; i <= endKey; i += 1)
2160                        ilist.remove(endKey - 1);
2161                    assertEquals(alist, list);
2162                }
2163            }
2164        });
2165    }
2166
2167    void readWriteRange(final int type, final int rangeBegin,
2168                        final int rangeEnd)
2169        throws Exception {
2170
2171        writeRunner.run(new TransactionWorker() {
2172            public void doWork() throws Exception {
2173                setRange(type, rangeBegin, rangeEnd);
2174                createOutOfRange(rangeBegin, rangeEnd);
2175                if (rangeType != TAIL) {
2176                    writeOutOfRange(new Long(rangeEnd + 1));
2177                }
2178                if (rangeType != HEAD) {
2179                    writeOutOfRange(new Long(rangeBegin - 1));
2180                }
2181                if (rangeBegin <= rangeEnd) {
2182                    updateAll();
2183                }
2184                if (rangeBegin < rangeEnd && !map.areKeysRenumbered()) {
2185                    bulkOperations();
2186                    removeIter();
2187                }
2188                readAll();
2189                clearRange();
2190            }
2191        });
2192    }
2193
2194    void setRange(int type, int rangeBegin, int rangeEnd) {
2195
2196        rangeType = type;
2197        saveMap = map;
2198        saveSMap = smap;
2199        saveList = list;
2200        int listBegin = rangeBegin - beginKey;
2201        boolean canMakeSubList = (list != null && listBegin>= 0);
2202        if (!canMakeSubList) {
2203            list = null;
2204        }
2205        if (list != null) {
2206            try {
2207                list.subList(-1, 0);
2208                fail();
2209            } catch (IndexOutOfBoundsException e) { }
2210        }
2211        switch (type) {
2212
2213        case SUB:
2214            smap = (StoredSortedMap) smap.subMap(makeKey(rangeBegin),
2215                                                 makeKey(rangeEnd + 1));
2216            if (canMakeSubList) {
2217                list = (StoredList) list.subList(listBegin,
2218                                                 rangeEnd + 1 - beginKey);
2219            }
2220            // check for equivalent ranges
2221            assertEquals(smap,
2222                        ((StoredSortedMap) saveSMap).subMap(
2223                            makeKey(rangeBegin), true,
2224                            makeKey(rangeEnd + 1), false));
2225            assertEquals(smap.entrySet(),
2226                        ((StoredSortedEntrySet) saveSMap.entrySet()).subSet(
2227                            mapEntry(rangeBegin), true,
2228                            mapEntry(rangeEnd + 1), false));
2229            assertEquals(smap.keySet(),
2230                        ((StoredSortedKeySet) saveSMap.keySet()).subSet(
2231                            makeKey(rangeBegin), true,
2232                            makeKey(rangeEnd + 1), false));
2233            if (smap.values() instanceof SortedSet) {
2234                assertEquals(smap.values(),
2235                            ((StoredSortedValueSet) saveSMap.values()).subSet(
2236                                makeVal(rangeBegin), true,
2237                                makeVal(rangeEnd + 1), false));
2238            }
2239            break;
2240        case HEAD:
2241            smap = (StoredSortedMap) smap.headMap(makeKey(rangeEnd + 1));
2242            if (canMakeSubList) {
2243                list = (StoredList) list.subList(0,
2244                                                 rangeEnd + 1 - beginKey);
2245            }
2246            // check for equivalent ranges
2247            assertEquals(smap,
2248                        ((StoredSortedMap) saveSMap).headMap(
2249                            makeKey(rangeEnd + 1), false));
2250            assertEquals(smap.entrySet(),
2251                        ((StoredSortedEntrySet) saveSMap.entrySet()).headSet(
2252                            mapEntry(rangeEnd + 1), false));
2253            assertEquals(smap.keySet(),
2254                        ((StoredSortedKeySet) saveSMap.keySet()).headSet(
2255                            makeKey(rangeEnd + 1), false));
2256            if (smap.values() instanceof SortedSet) {
2257                assertEquals(smap.values(),
2258                            ((StoredSortedValueSet) saveSMap.values()).headSet(
2259                                makeVal(rangeEnd + 1), false));
2260            }
2261            break;
2262        case TAIL:
2263            smap = (StoredSortedMap) smap.tailMap(makeKey(rangeBegin));
2264            if (canMakeSubList) {
2265                list = (StoredList) list.subList(listBegin,
2266                                                 maxKey + 1 - beginKey);
2267            }
2268            // check for equivalent ranges
2269            assertEquals(smap,
2270                        ((StoredSortedMap) saveSMap).tailMap(
2271                            makeKey(rangeBegin), true));
2272            assertEquals(smap.entrySet(),
2273                        ((StoredSortedEntrySet) saveSMap.entrySet()).tailSet(
2274                            mapEntry(rangeBegin), true));
2275            assertEquals(smap.keySet(),
2276                        ((StoredSortedKeySet) saveSMap.keySet()).tailSet(
2277                            makeKey(rangeBegin), true));
2278            if (smap.values() instanceof SortedSet) {
2279                assertEquals(smap.values(),
2280                            ((StoredSortedValueSet) saveSMap.values()).tailSet(
2281                                makeVal(rangeBegin), true));
2282            }
2283            break;
2284        default: throw new RuntimeException();
2285        }
2286        map = smap;
2287        beginKey = rangeBegin;
2288        if (rangeBegin < 1 || rangeEnd > maxKey) {
2289            endKey = rangeBegin - 1; // force empty range for readAll()
2290        } else {
2291            endKey = rangeEnd;
2292        }
2293    }
2294
2295    void clearRange() {
2296
2297        rangeType = NONE;
2298        beginKey = 1;
2299        endKey = maxKey;
2300        map = saveMap;
2301        smap = saveSMap;
2302        list = saveList;
2303    }
2304
2305    void createOutOfRange(int rangeBegin, int rangeEnd)
2306        throws Exception {
2307
2308        // map
2309
2310        if (rangeType != TAIL) {
2311            try {
2312                smap.subMap(makeKey(rangeBegin), makeKey(rangeEnd + 2));
2313                fail();
2314            } catch (IllegalArgumentException e) { }
2315            try {
2316                smap.headMap(makeKey(rangeEnd + 2));
2317                fail();
2318            } catch (IllegalArgumentException e) { }
2319            checkDupsSize(0, smap.duplicates(makeKey(rangeEnd + 2)));
2320        }
2321        if (rangeType != HEAD) {
2322            try {
2323                smap.subMap(makeKey(rangeBegin - 1), makeKey(rangeEnd + 1));
2324                fail();
2325            } catch (IllegalArgumentException e) { }
2326            try {
2327                smap.tailMap(makeKey(rangeBegin - 1));
2328                fail();
2329            } catch (IllegalArgumentException e) { }
2330            checkDupsSize(0, smap.duplicates(makeKey(rangeBegin - 1)));
2331        }
2332
2333        // keySet
2334
2335        if (rangeType != TAIL) {
2336            SortedSet sset = (SortedSet) map.keySet();
2337            try {
2338                sset.subSet(makeKey(rangeBegin), makeKey(rangeEnd + 2));
2339                fail();
2340            } catch (IllegalArgumentException e) { }
2341            try {
2342                sset.headSet(makeKey(rangeEnd + 2));
2343                fail();
2344            } catch (IllegalArgumentException e) { }
2345            try {
2346                iterator(sset.subSet(makeKey(rangeEnd + 1),
2347                                     makeKey(rangeEnd + 2)));
2348                fail();
2349            } catch (IllegalArgumentException e) { }
2350        }
2351        if (rangeType != HEAD) {
2352            SortedSet sset = (SortedSet) map.keySet();
2353            try {
2354                sset.subSet(makeKey(rangeBegin - 1), makeKey(rangeEnd + 1));
2355                fail();
2356            } catch (IllegalArgumentException e) { }
2357            try {
2358                sset.tailSet(makeKey(rangeBegin - 1));
2359                fail();
2360            } catch (IllegalArgumentException e) { }
2361            try {
2362                iterator(sset.subSet(makeKey(rangeBegin - 1),
2363                                     makeKey(rangeBegin)));
2364                fail();
2365            } catch (IllegalArgumentException e) { }
2366        }
2367
2368        // entrySet
2369
2370        if (rangeType != TAIL) {
2371            SortedSet sset = (SortedSet) map.entrySet();
2372            try {
2373                sset.subSet(mapEntry(rangeBegin), mapEntry(rangeEnd + 2));
2374                fail();
2375            } catch (IllegalArgumentException e) { }
2376            try {
2377                sset.headSet(mapEntry(rangeEnd + 2));
2378                fail();
2379            } catch (IllegalArgumentException e) { }
2380            try {
2381                iterator(sset.subSet(mapEntry(rangeEnd + 1),
2382                                     mapEntry(rangeEnd + 2)));
2383                fail();
2384            } catch (IllegalArgumentException e) { }
2385        }
2386        if (rangeType != HEAD) {
2387            SortedSet sset = (SortedSet) map.entrySet();
2388            try {
2389                sset.subSet(mapEntry(rangeBegin - 1), mapEntry(rangeEnd + 1));
2390                fail();
2391            } catch (IllegalArgumentException e) { }
2392            try {
2393                sset.tailSet(mapEntry(rangeBegin - 1));
2394                fail();
2395            } catch (IllegalArgumentException e) { }
2396            try {
2397                iterator(sset.subSet(mapEntry(rangeBegin - 1),
2398                                     mapEntry(rangeBegin)));
2399                fail();
2400            } catch (IllegalArgumentException e) { }
2401        }
2402
2403        // values
2404
2405        if (map.values() instanceof SortedSet) {
2406            SortedSet sset = (SortedSet) map.values();
2407            if (rangeType != TAIL) {
2408                try {
2409                    sset.subSet(makeVal(rangeBegin),
2410                                makeVal(rangeEnd + 2));
2411                    fail();
2412                } catch (IllegalArgumentException e) { }
2413                try {
2414                    sset.headSet(makeVal(rangeEnd + 2));
2415                    fail();
2416                } catch (IllegalArgumentException e) { }
2417            }
2418            if (rangeType != HEAD) {
2419                try {
2420                    sset.subSet(makeVal(rangeBegin - 1),
2421                                makeVal(rangeEnd + 1));
2422                    fail();
2423                } catch (IllegalArgumentException e) { }
2424                try {
2425                    sset.tailSet(makeVal(rangeBegin - 1));
2426                    fail();
2427                } catch (IllegalArgumentException e) { }
2428            }
2429        }
2430
2431        // list
2432
2433        if (list != null) {
2434            int size = rangeEnd - rangeBegin + 1;
2435            try {
2436                list.subList(0, size + 1);
2437                fail();
2438            } catch (IndexOutOfBoundsException e) { }
2439            try {
2440                list.subList(-1, size);
2441                fail();
2442            } catch (IndexOutOfBoundsException e) { }
2443            try {
2444                list.subList(2, 1);
2445                fail();
2446            } catch (IndexOutOfBoundsException e) { }
2447            try {
2448                list.subList(size, size);
2449                fail();
2450            } catch (IndexOutOfBoundsException e) { }
2451        }
2452    }
2453
2454    void writeOutOfRange(Long badNewKey)
2455        throws Exception {
2456
2457        try {
2458            map.put(badNewKey, makeVal(badNewKey));
2459            fail();
2460        } catch (IllegalArgumentException e) {
2461            assertTrue(e.toString(), index == null);
2462        } catch (UnsupportedOperationException e) {
2463            assertTrue(index != null);
2464        }
2465        try {
2466            map.keySet().add(badNewKey);
2467            fail();
2468        } catch (IllegalArgumentException e) {
2469            assertTrue(index == null);
2470        } catch (UnsupportedOperationException e) {
2471            assertTrue(index != null);
2472        }
2473        try {
2474            map.values().add(makeEntity(badNewKey));
2475            fail();
2476        } catch (IllegalArgumentException e) {
2477            assertTrue(isEntityBinding && index == null);
2478        } catch (UnsupportedOperationException e) {
2479            assertTrue(!(isEntityBinding && index == null));
2480        }
2481        if (list != null) {
2482            int i = badNewKey.intValue() - beginKey;
2483            try {
2484                list.set(i, makeVal(i));
2485                fail();
2486            } catch (IndexOutOfBoundsException e) {
2487                assertTrue(index == null);
2488            } catch (UnsupportedOperationException e) {
2489                assertTrue(index != null);
2490            }
2491            try {
2492                list.add(i, makeVal(badNewKey));
2493                fail();
2494            } catch (UnsupportedOperationException e) {
2495            }
2496        }
2497    }
2498
2499    void readWriteDuplicates()
2500        throws Exception {
2501
2502        writeRunner.run(new TransactionWorker() {
2503            public void doWork() throws Exception {
2504                if (index == null) {
2505                    readWritePrimaryDuplicates(beginKey);
2506                    readWritePrimaryDuplicates(beginKey + 1);
2507                    readWritePrimaryDuplicates(endKey);
2508                    readWritePrimaryDuplicates(endKey - 1);
2509                } else {
2510                    readWriteIndexedDuplicates(beginKey);
2511                    readWriteIndexedDuplicates(beginKey + 1);
2512                    readWriteIndexedDuplicates(endKey);
2513                    readWriteIndexedDuplicates(endKey - 1);
2514                }
2515            }
2516        });
2517    }
2518
2519    void readWritePrimaryDuplicates(int i)
2520        throws Exception {
2521
2522        Collection dups;
2523        // make duplicate values
2524        final Long key = makeKey(i);
2525        final Object[] values = new Object[5];
2526        for (int j = 0; j < values.length; j += 1) {
2527            values[j] = isEntityBinding
2528                        ? makeEntity(i, i + j)
2529                        : makeVal(i + j);
2530        }
2531        // add duplicates
2532        outerLoop: for (int writeMode = 0;; writeMode += 1) {
2533            //System.out.println("write mode " + writeMode);
2534            switch (writeMode) {
2535                case 0:
2536                case 1: {
2537                    // write with Map.put()
2538                    for (int j = 1; j < values.length; j += 1) {
2539                        map.put(key, values[j]);
2540                    }
2541                    break;
2542                }
2543                case 2: {
2544                    // write with Map.duplicates().add()
2545                    dups = map.duplicates(key);
2546                    for (int j = 1; j < values.length; j += 1) {
2547                        dups.add(values[j]);
2548                    }
2549                    break;
2550                }
2551                case 3: {
2552                    // write with Map.duplicates().iterator().add()
2553                    writeIterRunner.run(new TransactionWorker() {
2554                        public void doWork() throws Exception {
2555                            Collection dups = map.duplicates(key);
2556                            Iterator iter = iterator(dups);
2557                            assertEquals(values[0], iter.next());
2558                            assertTrue(!iter.hasNext());
2559                            try {
2560                                for (int j = 1; j < values.length; j += 1) {
2561                                    ((ListIterator) iter).add(values[j]);
2562                                }
2563                            } finally {
2564                                StoredIterator.close(iter);
2565                            }
2566                        }
2567                    });
2568                    break;
2569                }
2570                case 4: {
2571                    // write with Map.values().add()
2572                    if (!isEntityBinding) {
2573                        continue;
2574                    }
2575                    Collection set = map.values();
2576                    for (int j = 1; j < values.length; j += 1) {
2577                        set.add(values[j]);
2578                    }
2579                    break;
2580                }
2581                default: {
2582                    break outerLoop;
2583                }
2584            }
2585            checkDupsSize(values.length, map.duplicates(key));
2586            // read duplicates
2587            readDuplicates(i, key, values);
2588            // remove duplicates
2589            switch (writeMode) {
2590                case 0: {
2591                    // remove with Map.remove()
2592                    checkDupsSize(values.length, map.duplicates(key));
2593                    map.remove(key); // remove all values
2594                    checkDupsSize(0, map.duplicates(key));
2595                    map.put(key, values[0]); // put back original value
2596                    checkDupsSize(1, map.duplicates(key));
2597                    break;
2598                }
2599                case 1: {
2600                    // remove with Map.keySet().remove()
2601                    map.keySet().remove(key); // remove all values
2602                    map.put(key, values[0]); // put back original value
2603                    break;
2604                }
2605                case 2: {
2606                    // remove with Map.duplicates().clear()
2607                    dups = map.duplicates(key);
2608                    dups.clear(); // remove all values
2609                    dups.add(values[0]); // put back original value
2610                    break;
2611                }
2612                case 3: {
2613                    // remove with Map.duplicates().iterator().remove()
2614                    writeIterRunner.run(new TransactionWorker() {
2615                        public void doWork() throws Exception {
2616                            Collection dups = map.duplicates(key);
2617                            Iterator iter = iterator(dups);
2618                            try {
2619                                for (int j = 0; j < values.length; j += 1) {
2620                                    assertEquals(values[j], iter.next());
2621                                    if (j != 0) {
2622                                        iter.remove();
2623                                    }
2624                                }
2625                            } finally {
2626                                StoredIterator.close(iter);
2627                            }
2628                        }
2629                    });
2630                    break;
2631                }
2632                case 4: {
2633                    // remove with Map.values().remove()
2634                    if (!isEntityBinding) {
2635                        throw new IllegalStateException();
2636                    }
2637                    Collection set = map.values();
2638                    for (int j = 1; j < values.length; j += 1) {
2639                        set.remove(values[j]);
2640                    }
2641                    break;
2642                }
2643                default: throw new IllegalStateException();
2644            }
2645            // verify that only original value is present
2646            dups = map.duplicates(key);
2647            assertTrue(dups.contains(values[0]));
2648            for (int j = 1; j < values.length; j += 1) {
2649                assertTrue(!dups.contains(values[j]));
2650            }
2651            checkDupsSize(1, dups);
2652        }
2653    }
2654
2655    void readWriteIndexedDuplicates(int i)
2656        throws Exception {
2657
2658        Object key = makeKey(i);
2659        Object[] values = new Object[3];
2660        values[0] = makeVal(i);
2661        for (int j = 1; j < values.length; j += 1) {
2662            values[j] = isEntityBinding
2663                        ? makeEntity(endKey + j, i)
2664                        : makeVal(i);
2665        }
2666        // add duplicates
2667        for (int j = 1; j < values.length; j += 1) {
2668            imap.put(makeKey(endKey + j), values[j]);
2669        }
2670        // read duplicates
2671        readDuplicates(i, key, values);
2672        // remove duplicates
2673        for (int j = 1; j < values.length; j += 1) {
2674            imap.remove(makeKey(endKey + j));
2675        }
2676        checkDupsSize(1, map.duplicates(key));
2677    }
2678
2679    void readDuplicates(int i, Object key, Object[] values) {
2680
2681        boolean isOrdered = map.isOrdered();
2682        Collection dups;
2683        Iterator iter;
2684        // read with Map.duplicates().iterator()
2685        dups = map.duplicates(key);
2686        checkDupsSize(values.length, dups);
2687        iter = iterator(dups);
2688        try {
2689            for (int j = 0; j < values.length; j += 1) {
2690                assertTrue(iter.hasNext());
2691                Object val = iter.next();
2692                assertEquals(values[j], val);
2693            }
2694            assertTrue(!iter.hasNext());
2695        } finally {
2696            StoredIterator.close(iter);
2697        }
2698        // read with Map.values().iterator()
2699        Collection clone = ((StoredCollection) map.values()).toList();
2700        iter = iterator(map.values());
2701        try {
2702            for (int j = beginKey; j < i; j += 1) {
2703                Object val = iter.next();
2704                assertTrue(clone.remove(makeVal(j)));
2705                if (isOrdered) {
2706                    assertEquals(makeVal(j), val);
2707                }
2708            }
2709            for (int j = 0; j < values.length; j += 1) {
2710                Object val = iter.next();
2711                assertTrue(clone.remove(values[j]));
2712                if (isOrdered) {
2713                    assertEquals(values[j], val);
2714                }
2715            }
2716            for (int j = i + 1; j <= endKey; j += 1) {
2717                Object val = iter.next();
2718                assertTrue(clone.remove(makeVal(j)));
2719                if (isOrdered) {
2720                    assertEquals(makeVal(j), val);
2721                }
2722            }
2723            assertTrue(!iter.hasNext());
2724            assertTrue(clone.isEmpty());
2725        } finally {
2726            StoredIterator.close(iter);
2727        }
2728        // read with Map.entrySet().iterator()
2729        clone = ((StoredCollection) map.entrySet()).toList();
2730        iter = iterator(map.entrySet());
2731        try {
2732            for (int j = beginKey; j < i; j += 1) {
2733                Map.Entry entry = (Map.Entry) iter.next();
2734                assertTrue(clone.remove(mapEntry(j)));
2735                if (isOrdered) {
2736                    assertEquals(makeVal(j), entry.getValue());
2737                    assertEquals(makeKey(j), entry.getKey());
2738                }
2739            }
2740            for (int j = 0; j < values.length; j += 1) {
2741                Map.Entry entry = (Map.Entry) iter.next();
2742                assertTrue(clone.remove(mapEntry(makeKey(i), values[j])));
2743                if (isOrdered) {
2744                    assertEquals(values[j], entry.getValue());
2745                    assertEquals(makeKey(i), entry.getKey());
2746                }
2747            }
2748            for (int j = i + 1; j <= endKey; j += 1) {
2749                Map.Entry entry = (Map.Entry) iter.next();
2750                assertTrue(clone.remove(mapEntry(j)));
2751                if (isOrdered) {
2752                    assertEquals(makeVal(j), entry.getValue());
2753                    assertEquals(makeKey(j), entry.getKey());
2754                }
2755            }
2756            assertTrue(!iter.hasNext());
2757            assertTrue(clone.isEmpty());
2758        } finally {
2759            StoredIterator.close(iter);
2760        }
2761        // read with Map.keySet().iterator()
2762        clone = ((StoredCollection) map.keySet()).toList();
2763        iter = iterator(map.keySet());
2764        try {
2765            for (int j = beginKey; j < i; j += 1) {
2766                Object val = iter.next();
2767                assertTrue(clone.remove(makeKey(j)));
2768                if (isOrdered) {
2769                    assertEquals(makeKey(j), val);
2770                }
2771            }
2772            if (true) {
2773                // only one key is iterated for all duplicates
2774                Object val = iter.next();
2775                assertTrue(clone.remove(makeKey(i)));
2776                if (isOrdered) {
2777                    assertEquals(makeKey(i), val);
2778                }
2779            }
2780            for (int j = i + 1; j <= endKey; j += 1) {
2781                Object val = iter.next();
2782                assertTrue(clone.remove(makeKey(j)));
2783                if (isOrdered) {
2784                    assertEquals(makeKey(j), val);
2785                }
2786            }
2787            assertTrue(!iter.hasNext());
2788            assertTrue(clone.isEmpty());
2789        } finally {
2790            StoredIterator.close(iter);
2791        }
2792    }
2793
2794    void duplicatesNotAllowed() {
2795
2796        Collection dups = map.duplicates(makeKey(beginKey));
2797        try {
2798            dups.add(makeVal(beginKey));
2799            fail();
2800        } catch (UnsupportedOperationException expected) { }
2801        ListIterator iter = (ListIterator) iterator(dups);
2802        try {
2803            iter.add(makeVal(beginKey));
2804            fail();
2805        } catch (UnsupportedOperationException expected) {
2806        } finally {
2807            StoredIterator.close(iter);
2808        }
2809    }
2810
2811    void listOperationsNotAllowed() {
2812
2813        ListIterator iter = (ListIterator) iterator(map.values());
2814        try {
2815            try {
2816                iter.nextIndex();
2817                fail();
2818            } catch (UnsupportedOperationException expected) { }
2819            try {
2820                iter.previousIndex();
2821                fail();
2822            } catch (UnsupportedOperationException expected) { }
2823        } finally {
2824            StoredIterator.close(iter);
2825        }
2826    }
2827
2828    void testCdbLocking() {
2829
2830        Iterator readIterator;
2831        Iterator writeIterator;
2832        StoredKeySet set = (StoredKeySet) map.keySet();
2833
2834        // can open two CDB read cursors
2835        readIterator = set.storedIterator(false);
2836        try {
2837            Iterator readIterator2 = set.storedIterator(false);
2838            StoredIterator.close(readIterator2);
2839        } finally {
2840            StoredIterator.close(readIterator);
2841        }
2842
2843        // can open two CDB write cursors
2844        writeIterator = set.storedIterator(true);
2845        try {
2846            Iterator writeIterator2 = set.storedIterator(true);
2847            StoredIterator.close(writeIterator2);
2848        } finally {
2849            StoredIterator.close(writeIterator);
2850        }
2851
2852        // cannot open CDB write cursor when read cursor is open,
2853        readIterator = set.storedIterator(false);
2854        try {
2855            writeIterator = set.storedIterator(true);
2856            fail();
2857            StoredIterator.close(writeIterator);
2858        } catch (IllegalStateException e) {
2859        } finally {
2860            StoredIterator.close(readIterator);
2861        }
2862
2863        if (index == null) {
2864            // cannot put() with read cursor open
2865            readIterator = set.storedIterator(false);
2866            try {
2867                map.put(makeKey(1), makeVal(1));
2868                fail();
2869            } catch (IllegalStateException e) {
2870            } finally {
2871                StoredIterator.close(readIterator);
2872            }
2873
2874            // cannot append() with write cursor open with RECNO/QUEUE only
2875            writeIterator = set.storedIterator(true);
2876            try {
2877                if (testStore.isQueueOrRecno()) {
2878                    try {
2879                        map.append(makeVal(1));
2880                        fail();
2881                    } catch (IllegalStateException e) {}
2882                } else {
2883                    map.append(makeVal(1));
2884                }
2885            } finally {
2886                StoredIterator.close(writeIterator);
2887            }
2888        }
2889    }
2890
2891    Object makeVal(int key) {
2892
2893        if (isEntityBinding) {
2894            return makeEntity(key);
2895        } else {
2896            return new Long(key + 100);
2897        }
2898    }
2899
2900    Object makeVal(int key, int val) {
2901
2902        if (isEntityBinding) {
2903            return makeEntity(key, val);
2904        } else {
2905            return makeVal(val);
2906        }
2907    }
2908
2909    Object makeEntity(int key, int val) {
2910
2911        return new TestEntity(key, val + 100);
2912    }
2913
2914    int intVal(Object val) {
2915
2916        if (isEntityBinding) {
2917            return ((TestEntity) val).value - 100;
2918        } else {
2919            return ((Long) val).intValue() - 100;
2920        }
2921    }
2922
2923    int intKey(Object key) {
2924
2925        return ((Long) key).intValue();
2926    }
2927
2928    Object makeVal(Long key) {
2929
2930        return makeVal(key.intValue());
2931    }
2932
2933    Object makeEntity(int key) {
2934
2935        return makeEntity(key, key);
2936    }
2937
2938    Object makeEntity(Long key) {
2939
2940        return makeEntity(key.intValue());
2941    }
2942
2943    int intIter(Collection coll, Object value) {
2944
2945        if (coll instanceof StoredKeySet) {
2946            return intKey(value);
2947        } else {
2948            if (coll instanceof StoredEntrySet) {
2949                value = ((Map.Entry) value).getValue();
2950            }
2951            return intVal(value);
2952        }
2953    }
2954
2955    Map.Entry mapEntry(Object key, Object val) {
2956
2957        return new MapEntryParameter(key, val);
2958    }
2959
2960    Map.Entry mapEntry(int key) {
2961
2962        return new MapEntryParameter(makeKey(key), makeVal(key));
2963    }
2964
2965    Long makeKey(int key) {
2966
2967        return new Long(key);
2968    }
2969
2970    boolean isSubMap() {
2971
2972        return rangeType != NONE;
2973    }
2974
2975    void checkDupsSize(int expected, Collection coll) {
2976
2977        assertEquals(expected, coll.size());
2978        if (coll instanceof StoredCollection) {
2979            StoredIterator i = ((StoredCollection) coll).storedIterator(false);
2980            try {
2981                int actual = 0;
2982                if (i.hasNext()) {
2983                    i.next();
2984                    actual = i.count();
2985                }
2986                assertEquals(expected, actual);
2987            } finally {
2988                StoredIterator.close(i);
2989            }
2990        }
2991    }
2992
2993    private boolean isListAddAllowed() {
2994
2995        return list != null && testStore.isQueueOrRecno() &&
2996               list.areKeysRenumbered();
2997    }
2998
2999    private int countElements(Collection coll) {
3000
3001        int count = 0;
3002        Iterator iter = iterator(coll);
3003        try {
3004            while (iter.hasNext()) {
3005                iter.next();
3006                count += 1;
3007            }
3008        } finally {
3009            StoredIterator.close(iter);
3010        }
3011        return count;
3012    }
3013}
3014