1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.mavibot.btree;
21
22
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28
29 import java.io.File;
30 import java.io.IOException;
31 import java.util.NoSuchElementException;
32 import java.util.UUID;
33
34 import org.apache.commons.io.FileUtils;
35 import org.apache.directory.mavibot.btree.BTree;
36 import org.apache.directory.mavibot.btree.RecordManager;
37 import org.apache.directory.mavibot.btree.Tuple;
38 import org.apache.directory.mavibot.btree.TupleCursor;
39 import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
40 import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
41 import org.apache.directory.mavibot.btree.serializer.LongSerializer;
42 import org.apache.directory.mavibot.btree.serializer.StringSerializer;
43 import org.junit.After;
44 import org.junit.Before;
45 import org.junit.Rule;
46 import org.junit.Test;
47 import org.junit.rules.TemporaryFolder;
48
49
50
51
52
53
54
55 public class PersistedBTreeBrowseTest
56 {
57 private BTree<Long, String> btree = null;
58
59 private RecordManager recordManager1 = null;
60
61 @Rule
62 public TemporaryFolder tempFolder = new TemporaryFolder();
63
64 private File dataDir = null;
65
66
67
68
69
70 @Before
71 public void createBTree()
72 {
73 dataDir = tempFolder.newFolder( UUID.randomUUID().toString() );
74
75 openRecordManagerAndBtree();
76
77 try
78 {
79
80 btree = recordManager1.addBTree( "test", new LongSerializer(), new StringSerializer(), true );
81 }
82 catch ( Exception e )
83 {
84 throw new RuntimeException( e );
85 }
86 }
87
88
89 @After
90 public void cleanup() throws IOException
91 {
92 dataDir = new File( System.getProperty( "java.io.tmpdir" ) + "/recordman" );
93
94 btree.close();
95
96 if ( dataDir.exists() )
97 {
98 FileUtils.deleteDirectory( dataDir );
99 }
100 }
101
102
103
104
105
106 private void openRecordManagerAndBtree()
107 {
108 try
109 {
110 if ( recordManager1 != null )
111 {
112 recordManager1.close();
113 }
114
115
116 recordManager1 = new RecordManager( dataDir.getAbsolutePath() );
117
118
119 if ( btree != null )
120 {
121 btree = recordManager1.getManagedTree( btree.getName() );
122 }
123 }
124 catch ( Exception e )
125 {
126 throw new RuntimeException( e );
127 }
128 }
129
130
131
132
133
134 private void checkTuple( Tuple<Long, String> tuple, long key, String value ) throws EndOfFileExceededException,
135 IOException
136 {
137 assertNotNull( tuple );
138 assertEquals( key, ( long ) tuple.getKey() );
139 assertEquals( value, tuple.getValue() );
140 }
141
142
143
144
145
146 private void checkNext( TupleCursor<Long, String> cursor, long key, String value, boolean next, boolean prev )
147 throws EndOfFileExceededException, IOException
148 {
149 Tuple<Long, String> tuple = cursor.next();
150
151 checkTuple( tuple, key, value );
152 assertEquals( next, cursor.hasNext() );
153 assertEquals( prev, cursor.hasPrev() );
154 }
155
156
157
158
159
160 private void checkPrev( TupleCursor<Long, String> cursor, long key, String value, boolean next, boolean prev )
161 throws EndOfFileExceededException, IOException
162 {
163 Tuple<Long, String> tuple = cursor.prev();
164 assertNotNull( tuple );
165 assertEquals( key, ( long ) tuple.getKey() );
166 assertEquals( value, tuple.getValue() );
167 assertEquals( next, cursor.hasNext() );
168 assertEquals( prev, cursor.hasPrev() );
169 }
170
171
172
173
174
175 private String toString( long value, int size )
176 {
177 String valueStr = Long.toString( value );
178
179 StringBuilder sb = new StringBuilder();
180
181 if ( size > valueStr.length() )
182 {
183 for ( int i = valueStr.length(); i < size; i++ )
184 {
185 sb.append( "0" );
186 }
187 }
188
189 sb.append( valueStr );
190
191 return sb.toString();
192 }
193
194
195
196
197
198
199
200
201 @Test
202 public void testBrowseEmptyBTree() throws IOException, BTreeAlreadyManagedException
203 {
204 TupleCursor<Long, String> cursor = btree.browse();
205
206 assertFalse( cursor.hasNext() );
207 assertFalse( cursor.hasPrev() );
208
209 try
210 {
211 cursor.next();
212 fail();
213 }
214 catch ( NoSuchElementException nsee )
215 {
216
217 }
218
219 try
220 {
221 cursor.prev();
222 fail();
223 }
224 catch ( NoSuchElementException nsee )
225 {
226
227 }
228
229 assertEquals( -1L, cursor.getRevision() );
230 }
231
232
233
234
235
236 @Test
237 public void testBrowseBTreeLeafNext() throws IOException, BTreeAlreadyManagedException
238 {
239
240 btree.insert( 1L, "1" );
241 btree.insert( 4L, "4" );
242 btree.insert( 2L, "2" );
243 btree.insert( 3L, "3" );
244 btree.insert( 5L, "5" );
245
246
247 TupleCursor<Long, String> cursor = btree.browse();
248
249
250 cursor.beforeFirst();
251
252 assertFalse( cursor.hasPrev() );
253 assertTrue( cursor.hasNext() );
254
255 checkNext( cursor, 1L, "1", true, false );
256 checkNext( cursor, 2L, "2", true, true );
257 checkNext( cursor, 3L, "3", true, true );
258 checkNext( cursor, 4L, "4", true, true );
259 checkNext( cursor, 5L, "5", false, true );
260 }
261
262
263
264
265
266 @Test
267 public void testBrowseBTreeLeafPrev() throws IOException, BTreeAlreadyManagedException
268 {
269
270 btree.insert( 1L, "1" );
271 btree.insert( 4L, "4" );
272 btree.insert( 2L, "2" );
273 btree.insert( 3L, "3" );
274 btree.insert( 5L, "5" );
275
276
277 TupleCursor<Long, String> cursor = btree.browse();
278
279
280 cursor.afterLast();
281
282 checkPrev( cursor, 5L, "5", false, true );
283 checkPrev( cursor, 4L, "4", true, true );
284 checkPrev( cursor, 3L, "3", true, true );
285 checkPrev( cursor, 2L, "2", true, true );
286 checkPrev( cursor, 1L, "1", true, false );
287 }
288
289
290
291
292
293
294 @Test
295 public void testBrowseBTreeLeafFirstLast() throws IOException, BTreeAlreadyManagedException
296 {
297
298 btree.insert( 1L, "1" );
299 btree.insert( 4L, "4" );
300 btree.insert( 2L, "2" );
301 btree.insert( 3L, "3" );
302 btree.insert( 5L, "5" );
303
304
305 TupleCursor<Long, String> cursor = btree.browse();
306
307
308 try
309 {
310 cursor.prev();
311 fail();
312 }
313 catch ( NoSuchElementException nsee )
314 {
315
316 }
317
318
319 assertFalse( cursor.hasPrev() );
320 assertTrue( cursor.hasNext() );
321 Tuple<Long, String> tuple = cursor.next();
322 tuple = cursor.next();
323 tuple = cursor.next();
324
325
326 assertTrue( cursor.hasPrev() );
327 assertTrue( cursor.hasNext() );
328 assertEquals( 3L, ( long ) tuple.getKey() );
329 assertEquals( "3", tuple.getValue() );
330
331
332 cursor.afterLast();
333
334 assertTrue( cursor.hasPrev() );
335 assertFalse( cursor.hasNext() );
336
337
338 try
339 {
340 cursor.next();
341 fail();
342 }
343 catch ( NoSuchElementException nsee )
344 {
345
346 }
347
348
349 tuple = cursor.prev();
350 assertEquals( 5L, ( long ) tuple.getKey() );
351 assertEquals( "5", tuple.getValue() );
352
353 assertTrue( cursor.hasPrev() );
354 assertFalse( cursor.hasNext() );
355
356
357 cursor.beforeFirst();
358
359 assertFalse( cursor.hasPrev() );
360 assertTrue( cursor.hasNext() );
361
362
363 tuple = cursor.next();
364 assertEquals( 1L, ( long ) tuple.getKey() );
365 assertEquals( "1", tuple.getValue() );
366
367 assertFalse( cursor.hasPrev() );
368 assertTrue( cursor.hasNext() );
369 }
370
371
372
373
374
375
376 @Test
377 public void testBrowseBTreeLeafNextPrev() throws IOException, BTreeAlreadyManagedException
378 {
379
380 btree.insert( 1L, "1" );
381 btree.insert( 4L, "4" );
382 btree.insert( 2L, "2" );
383 btree.insert( 3L, "3" );
384 btree.insert( 5L, "5" );
385
386
387 TupleCursor<Long, String> cursor = btree.browse();
388
389
390 try
391 {
392 cursor.prev();
393 fail();
394 }
395 catch ( NoSuchElementException nsee )
396 {
397
398 }
399
400
401 assertFalse( cursor.hasPrev() );
402 assertTrue( cursor.hasNext() );
403 Tuple<Long, String> tuple = cursor.next();
404 tuple = cursor.next();
405 tuple = cursor.next();
406
407
408 assertTrue( cursor.hasPrev() );
409 assertTrue( cursor.hasNext() );
410 assertEquals( 3L, ( long ) tuple.getKey() );
411 assertEquals( "3", tuple.getValue() );
412
413
414 cursor.prev();
415 assertEquals( 2L, ( long ) tuple.getKey() );
416 assertEquals( "2", tuple.getValue() );
417
418
419 cursor.next();
420 assertEquals( 3L, ( long ) tuple.getKey() );
421 assertEquals( "3", tuple.getValue() );
422 }
423
424
425
426
427
428 @Test
429 public void testBrowseBTreeNodesNext() throws IOException, BTreeAlreadyManagedException
430 {
431
432 for ( long i = 1; i < 1000L; i++ )
433 {
434 btree.insert( i, Long.toString( i ) );
435 }
436
437
438 TupleCursor<Long, String> cursor = btree.browse();
439
440
441 cursor.beforeFirst();
442
443 assertFalse( cursor.hasPrev() );
444 assertTrue( cursor.hasNext() );
445
446 checkNext( cursor, 1L, "1", true, false );
447
448 for ( long i = 2L; i < 999L; i++ )
449 {
450 checkNext( cursor, i, Long.toString( i ), true, true );
451 }
452
453 checkNext( cursor, 999L, "999", false, true );
454 }
455
456
457
458
459
460 @Test
461 public void testBrowseBTreeNodesPrev() throws IOException, BTreeAlreadyManagedException
462 {
463
464 for ( long i = 1; i < 1000L; i++ )
465 {
466 btree.insert( i, Long.toString( i ) );
467 }
468
469
470 TupleCursor<Long, String> cursor = btree.browse();
471
472
473 cursor.afterLast();
474
475 assertTrue( cursor.hasPrev() );
476 assertFalse( cursor.hasNext() );
477
478 checkPrev( cursor, 999L, "999", false, true );
479
480 for ( long i = 998L; i > 1L; i-- )
481 {
482 checkPrev( cursor, i, Long.toString( i ), true, true );
483 }
484
485 checkPrev( cursor, 1L, "1", true, false );
486 }
487
488
489
490
491
492 @Test
493 public void testBrowseBTreeLeafNextDups1() throws IOException, BTreeAlreadyManagedException
494 {
495
496 btree.insert( 1L, "1" );
497 btree.insert( 1L, "4" );
498 btree.insert( 1L, "2" );
499 btree.insert( 1L, "3" );
500 btree.insert( 1L, "5" );
501
502
503 TupleCursor<Long, String> cursor = btree.browse();
504
505
506 cursor.beforeFirst();
507
508 assertFalse( cursor.hasPrev() );
509 assertTrue( cursor.hasNext() );
510
511 checkNext( cursor, 1L, "1", true, false );
512 checkNext( cursor, 1L, "2", true, true );
513 checkNext( cursor, 1L, "3", true, true );
514 checkNext( cursor, 1L, "4", true, true );
515 checkNext( cursor, 1L, "5", false, true );
516 }
517
518
519
520
521
522 @Test
523 public void testBrowseBTreeLeafNextDupsN() throws IOException, BTreeAlreadyManagedException
524 {
525
526 btree.insert( 1L, "1" );
527 btree.insert( 1L, "4" );
528 btree.insert( 1L, "2" );
529 btree.insert( 2L, "3" );
530 btree.insert( 3L, "5" );
531 btree.insert( 3L, "7" );
532 btree.insert( 3L, "6" );
533
534
535 TupleCursor<Long, String> cursor = btree.browse();
536
537
538 cursor.beforeFirst();
539
540 assertFalse( cursor.hasPrev() );
541 assertTrue( cursor.hasNext() );
542
543 checkNext( cursor, 1L, "1", true, false );
544 checkNext( cursor, 1L, "2", true, true );
545 checkNext( cursor, 1L, "4", true, true );
546 checkNext( cursor, 2L, "3", true, true );
547 checkNext( cursor, 3L, "5", true, true );
548 checkNext( cursor, 3L, "6", true, true );
549 checkNext( cursor, 3L, "7", false, true );
550 }
551
552
553
554
555
556 @Test
557 public void testBrowseBTreeLeafPrevDups1() throws IOException, BTreeAlreadyManagedException
558 {
559
560 btree.insert( 1L, "1" );
561 btree.insert( 1L, "4" );
562 btree.insert( 1L, "2" );
563 btree.insert( 1L, "3" );
564 btree.insert( 1L, "5" );
565
566
567 TupleCursor<Long, String> cursor = btree.browse();
568
569
570 cursor.afterLast();
571
572 assertTrue( cursor.hasPrev() );
573 assertFalse( cursor.hasNext() );
574
575 checkPrev( cursor, 1L, "5", false, true );
576 checkPrev( cursor, 1L, "4", true, true );
577 checkPrev( cursor, 1L, "3", true, true );
578 checkPrev( cursor, 1L, "2", true, true );
579 checkPrev( cursor, 1L, "1", true, false );
580 }
581
582
583
584
585
586 @Test
587 public void testBrowseBTreeLeafPrevDupsN() throws IOException, BTreeAlreadyManagedException
588 {
589
590 btree.insert( 1L, "1" );
591 btree.insert( 1L, "4" );
592 btree.insert( 1L, "2" );
593 btree.insert( 2L, "3" );
594 btree.insert( 3L, "5" );
595 btree.insert( 3L, "7" );
596 btree.insert( 3L, "6" );
597
598
599 TupleCursor<Long, String> cursor = btree.browse();
600
601
602 cursor.afterLast();
603
604 assertTrue( cursor.hasPrev() );
605 assertFalse( cursor.hasNext() );
606
607 checkPrev( cursor, 3L, "7", false, true );
608 checkPrev( cursor, 3L, "6", true, true );
609 checkPrev( cursor, 3L, "5", true, true );
610 checkPrev( cursor, 2L, "3", true, true );
611 checkPrev( cursor, 1L, "4", true, true );
612 checkPrev( cursor, 1L, "2", true, true );
613 checkPrev( cursor, 1L, "1", true, false );
614 }
615
616
617
618
619
620 @Test
621 public void testBrowseBTreeNodesNextDupsN() throws IOException, BTreeAlreadyManagedException
622 {
623
624 for ( long i = 1; i < 1000L; i++ )
625 {
626 for ( long j = 1; j < 10; j++ )
627 {
628 btree.insert( i, Long.toString( j ) );
629 }
630 }
631
632
633 TupleCursor<Long, String> cursor = btree.browse();
634
635
636 cursor.beforeFirst();
637
638 assertFalse( cursor.hasPrev() );
639 assertTrue( cursor.hasNext() );
640 boolean next = true;
641 boolean prev = false;
642
643 for ( long i = 1L; i < 1000L; i++ )
644 {
645 for ( long j = 1L; j < 10L; j++ )
646 {
647 checkNext( cursor, i, Long.toString( j ), next, prev );
648
649 if ( ( i == 1L ) && ( j == 1L ) )
650 {
651 prev = true;
652 }
653
654 if ( ( i == 999L ) && ( j == 8L ) )
655 {
656 next = false;
657 }
658 }
659 }
660 }
661
662
663
664
665
666 @Test
667 public void testBrowseBTreeNodesPrevDupsN() throws IOException, BTreeAlreadyManagedException
668 {
669
670 for ( long i = 1; i < 1000L; i++ )
671 {
672 for ( int j = 1; j < 10; j++ )
673 {
674 btree.insert( i, Long.toString( j ) );
675 }
676 }
677
678
679 TupleCursor<Long, String> cursor = btree.browse();
680
681
682 cursor.afterLast();
683
684 assertTrue( cursor.hasPrev() );
685 assertFalse( cursor.hasNext() );
686 boolean next = false;
687 boolean prev = true;
688
689 for ( long i = 999L; i > 0L; i-- )
690 {
691 for ( long j = 9L; j > 0L; j-- )
692 {
693 checkPrev( cursor, i, Long.toString( j ), next, prev );
694
695 if ( ( i == 1L ) && ( j == 2L ) )
696 {
697 prev = false;
698 }
699
700 if ( ( i == 999L ) && ( j == 9L ) )
701 {
702 next = true;
703 }
704 }
705 }
706 }
707
708
709
710
711
712
713 @Test
714 public void testBrowseBTreeLeafNextDupsSubBTree1() throws IOException, BTreeAlreadyManagedException
715 {
716
717 for ( long i = 1L; i < 32L; i++ )
718 {
719 btree.insert( 1L, toString( i, 2 ) );
720 }
721
722
723 TupleCursor<Long, String> cursor = btree.browse();
724
725
726 cursor.beforeFirst();
727
728 assertFalse( cursor.hasPrev() );
729 assertTrue( cursor.hasNext() );
730
731 checkNext( cursor, 1L, "01", true, false );
732
733 for ( long i = 2L; i < 31L; i++ )
734 {
735 checkNext( cursor, 1L, toString( i, 2 ), true, true );
736 }
737
738 checkNext( cursor, 1L, "31", false, true );
739 }
740
741
742
743
744
745 @Test
746 public void testBrowseBTreeLeafPrevDupsSubBTree1() throws IOException, BTreeAlreadyManagedException
747 {
748
749 for ( long i = 1L; i < 32L; i++ )
750 {
751 btree.insert( 1L, toString( i, 2 ) );
752 }
753
754
755 TupleCursor<Long, String> cursor = btree.browse();
756
757
758 cursor.afterLast();
759
760 assertTrue( cursor.hasPrev() );
761 assertFalse( cursor.hasNext() );
762
763 checkPrev( cursor, 1L, "31", false, true );
764
765 for ( long i = 30L; i > 1L; i-- )
766 {
767 checkPrev( cursor, 1L, toString( i, 2 ), true, true );
768 }
769
770 checkPrev( cursor, 1L, "01", true, false );
771 }
772
773
774
775
776
777
778
779
780 @Test
781 public void testBrowseFromEmptyBTree() throws IOException, BTreeAlreadyManagedException
782 {
783 TupleCursor<Long, String> cursor = btree.browseFrom( 1L );
784
785 assertFalse( cursor.hasNext() );
786 assertFalse( cursor.hasPrev() );
787
788 try
789 {
790 cursor.next();
791 fail();
792 }
793 catch ( NoSuchElementException nsee )
794 {
795
796 }
797
798 try
799 {
800 cursor.prev();
801 fail();
802 }
803 catch ( NoSuchElementException nsee )
804 {
805
806 }
807
808 assertEquals( -1L, cursor.getRevision() );
809 }
810
811
812
813
814
815 @Test
816 public void testBrowseFromBTreeLeaf() throws IOException, BTreeAlreadyManagedException
817 {
818
819 btree.insert( 1L, "1" );
820 btree.insert( 7L, "7" );
821 btree.insert( 3L, "3" );
822 btree.insert( 5L, "5" );
823 btree.insert( 9L, "9" );
824
825
826 TupleCursor<Long, String> cursor = btree.browseFrom( 5L );
827
828 assertTrue( cursor.hasPrev() );
829 assertTrue( cursor.hasNext() );
830
831
832 checkNext( cursor, 5L, "5", true, true );
833 checkNext( cursor, 7L, "7", true, true );
834 checkNext( cursor, 9L, "9", false, true );
835
836 cursor.close();
837
838
839 cursor = btree.browseFrom( 5L );
840
841 assertTrue( cursor.hasPrev() );
842 assertTrue( cursor.hasNext() );
843
844
845 checkPrev( cursor, 3L, "3", true, true );
846 checkPrev( cursor, 1L, "1", true, false );
847 cursor.close();
848
849
850 cursor = btree.browseFrom( 1L );
851 assertFalse( cursor.hasPrev() );
852 assertTrue( cursor.hasNext() );
853
854 checkNext( cursor, 1L, "1", true, false );
855 checkNext( cursor, 3L, "3", true, true );
856
857
858 cursor = btree.browseFrom( 0L );
859 assertFalse( cursor.hasPrev() );
860 assertTrue( cursor.hasNext() );
861
862 checkNext( cursor, 1L, "1", true, false );
863 checkNext( cursor, 3L, "3", true, true );
864
865
866 cursor = btree.browseFrom( 9L );
867 assertTrue( cursor.hasPrev() );
868 assertTrue( cursor.hasNext() );
869
870 checkNext( cursor, 9L, "9", false, true );
871 checkPrev( cursor, 7L, "7", true, true );
872
873
874 cursor = btree.browseFrom( 10L );
875 assertTrue( cursor.hasPrev() );
876 assertFalse( cursor.hasNext() );
877
878 checkPrev( cursor, 9L, "9", false, true );
879 checkPrev( cursor, 7L, "7", true, true );
880
881
882 cursor = btree.browseFrom( 4L );
883 assertTrue( cursor.hasPrev() );
884 assertTrue( cursor.hasNext() );
885
886 checkNext( cursor, 5L, "5", true, true );
887
888
889 cursor = btree.browseFrom( 4L );
890
891 checkPrev( cursor, 3L, "3", true, true );
892 }
893
894
895
896
897
898 @Test
899 public void testBrowseFromBTreeNodesPrevDupsN() throws IOException, BTreeAlreadyManagedException
900 {
901
902 for ( long i = 1; i < 1000L; i += 2 )
903 {
904 for ( int j = 1; j < 10; j++ )
905 {
906 btree.insert( i, Long.toString( j ) );
907 }
908 }
909
910
911 TupleCursor<Long, String> cursor = btree.browseFrom( 500L );
912
913
914
915 assertTrue( cursor.hasPrev() );
916 assertTrue( cursor.hasNext() );
917 boolean next = true;
918 boolean prev = true;
919
920 for ( long i = 501L; i < 1000L; i += 2 )
921 {
922 for ( long j = 1L; j < 10L; j++ )
923 {
924 if ( ( i == 999L ) && ( j == 9L ) )
925 {
926 next = false;
927 }
928
929 checkNext( cursor, i, Long.toString( j ), next, prev );
930 }
931 }
932 }
933
934
935
936
937
938
939
940
941
942 @Test
943 public void testNextKey() throws IOException, BTreeAlreadyManagedException
944 {
945
946 for ( long i = 1; i < 1000L; i++ )
947 {
948 for ( long j = 1; j < 10; j++ )
949 {
950 btree.insert( i, Long.toString( j ) );
951 }
952 }
953
954
955 TupleCursor<Long, String> cursor = btree.browse();
956
957
958 cursor.beforeFirst();
959
960 assertFalse( cursor.hasPrev() );
961 assertTrue( cursor.hasNext() );
962 boolean next = true;
963 boolean prev = false;
964
965 for ( long i = 1L; i < 999L; i++ )
966 {
967 Tuple<Long, String> tuple = cursor.nextKey();
968
969 checkTuple( tuple, i, "1" );
970
971 if ( i == 999L )
972 {
973 next = false;
974 }
975
976 assertEquals( next, cursor.hasNext() );
977 assertEquals( prev, cursor.hasPrev() );
978
979 if ( i == 1L )
980 {
981 prev = true;
982 }
983 }
984 }
985
986
987
988
989
990
991 @Test
992 public void testPrevKey() throws IOException, BTreeAlreadyManagedException
993 {
994
995 for ( long i = 1; i < 1000L; i++ )
996 {
997 for ( long j = 1; j < 10; j++ )
998 {
999 btree.insert( i, Long.toString( j ) );
1000 }
1001 }
1002
1003
1004 TupleCursor<Long, String> cursor = btree.browse();
1005
1006
1007 cursor.afterLast();
1008
1009 assertTrue( cursor.hasPrev() );
1010 assertFalse( cursor.hasNext() );
1011 boolean next = true;
1012 boolean prev = true;
1013
1014 for ( long i = 999L; i > 0L; i-- )
1015 {
1016 Tuple<Long, String> tuple = cursor.prevKey();
1017
1018 if ( i == 1L )
1019 {
1020 prev = false;
1021 }
1022
1023 checkTuple( tuple, i, "1" );
1024 assertEquals( next, cursor.hasNext() );
1025 assertEquals( prev, cursor.hasPrev() );
1026
1027 if ( i == 999L )
1028 {
1029 next = true;
1030 }
1031 }
1032 }
1033 }