1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002, 2014 Oracle and/or its affiliates.  All rights reserved.
5  *
6  */
7 
8 package com.sleepycat.bind.tuple.test;
9 
10 import static org.junit.Assert.fail;
11 
12 import java.math.BigDecimal;
13 import java.math.BigInteger;
14 
15 import org.junit.After;
16 import org.junit.Before;
17 import org.junit.Test;
18 
19 import com.sleepycat.bind.tuple.TupleOutput;
20 
21 /**
22  * @author Mark Hayes
23  */
24 public class TupleOrderingTest {
25 
26     private TupleOutput out;
27     private byte[] prevBuf;
28 
29     @Before
setUp()30     public void setUp() {
31 
32         out = new TupleOutput();
33         prevBuf = null;
34     }
35 
36     @After
tearDown()37     public void tearDown() {
38 
39         /* Ensure that GC can cleanup. */
40         out = null;
41         prevBuf = null;
42     }
43 
44     /**
45      * Each tuple written must be strictly less than (by comparison of bytes)
46      * the tuple written just before it.  The check() method compares bytes
47      * just written to those written before the previous call to check().
48      */
check()49     private void check() {
50 
51         check(-1);
52     }
53 
check(int dataIndex)54     private void check(int dataIndex) {
55 
56         byte[] buf = new byte[out.size()];
57         System.arraycopy(out.getBufferBytes(), out.getBufferOffset(),
58                          buf, 0, buf.length);
59         if (prevBuf != null) {
60             int errOffset = -1;
61             int len = Math.min(prevBuf.length, buf.length);
62             boolean areEqual = true;
63             for (int i = 0; i < len; i += 1) {
64                 int val1 = prevBuf[i] & 0xFF;
65                 int val2 = buf[i] & 0xFF;
66                 if (val1 < val2) {
67                     areEqual = false;
68                     break;
69                 } else if (val1 > val2) {
70                     errOffset = i;
71                     break;
72                 }
73             }
74             if (areEqual) {
75                 if (prevBuf.length < buf.length) {
76                     areEqual = false;
77                 } else if (prevBuf.length > buf.length) {
78                     areEqual = false;
79                     errOffset = buf.length + 1;
80                 }
81             }
82             if (errOffset != -1 || areEqual) {
83                 StringBuilder msg = new StringBuilder();
84                 if (errOffset != -1) {
85                     msg.append("Left >= right at byte offset " + errOffset);
86                 } else if (areEqual) {
87                     msg.append("Bytes are equal");
88                 } else {
89                     throw new IllegalStateException();
90                 }
91                 msg.append("\nLeft hex bytes: ");
92                 for (int i = 0; i < prevBuf.length; i += 1) {
93                     msg.append(' ');
94                     int val = prevBuf[i] & 0xFF;
95                     if ((val & 0xF0) == 0) {
96                         msg.append('0');
97                     }
98                     msg.append(Integer.toHexString(val));
99                 }
100                 msg.append("\nRight hex bytes:");
101                 for (int i = 0; i < buf.length; i += 1) {
102                     msg.append(' ');
103                     int val = buf[i] & 0xFF;
104                     if ((val & 0xF0) == 0) {
105                         msg.append('0');
106                     }
107                     msg.append(Integer.toHexString(val));
108                 }
109                 if (dataIndex >= 0) {
110                     msg.append("\nData index: " + dataIndex);
111                 }
112                 fail(msg.toString());
113             }
114         }
115         prevBuf = buf;
116         out.reset();
117     }
118 
reset()119     private void reset() {
120 
121         prevBuf = null;
122         out.reset();
123     }
124 
125     @Test
testString()126     public void testString() {
127 
128         final String[] DATA = {
129             "", "\u0001", "\u0002",
130             "A", "a", "ab", "b", "bb", "bba",
131             "c", "c\u0001", "d",
132             new String(new char[] { 0x7F }),
133             new String(new char[] { 0x7F, 0 }),
134             new String(new char[] { 0xFF }),
135             new String(new char[] { Character.MAX_VALUE }),
136         };
137         for (int i = 0; i < DATA.length; i += 1) {
138             out.writeString(DATA[i]);
139             check(i);
140         }
141         reset();
142         out.writeString("a");
143         check();
144         out.writeString("a");
145         out.writeString("");
146         check();
147         out.writeString("a");
148         out.writeString("");
149         out.writeString("a");
150         check();
151         out.writeString("a");
152         out.writeString("b");
153         check();
154         out.writeString("aa");
155         check();
156         out.writeString("b");
157         check();
158     }
159 
160     @Test
testFixedString()161     public void testFixedString() {
162 
163         final char[][] DATA = {
164             {}, {'a'}, {'a', 'b'}, {'b'}, {'b', 'b'}, {0x7F}, {0xFF},
165         };
166         for (int i = 0; i < DATA.length; i += 1) {
167             out.writeString(DATA[i]);
168             check(i);
169         }
170     }
171 
172     @Test
testChars()173     public void testChars() {
174 
175         final char[][] DATA = {
176             {}, {0}, {'a'}, {'a', 0}, {'a', 'b'}, {'b'}, {'b', 'b'},
177             {0x7F}, {0x7F, 0}, {0xFF}, {0xFF, 0},
178         };
179         for (int i = 0; i < DATA.length; i += 1) {
180             out.writeChars(DATA[i]);
181             check(i);
182         }
183     }
184 
185     @Test
testBytes()186     public void testBytes() {
187 
188         final char[][] DATA = {
189             {}, {0}, {'a'}, {'a', 0}, {'a', 'b'}, {'b'}, {'b', 'b'},
190             {0x7F}, {0xFF},
191         };
192         for (int i = 0; i < DATA.length; i += 1) {
193             out.writeBytes(DATA[i]);
194             check(i);
195         }
196     }
197 
198     @Test
testBoolean()199     public void testBoolean() {
200 
201         final boolean[] DATA = {
202             false, true
203         };
204         for (int i = 0; i < DATA.length; i += 1) {
205             out.writeBoolean(DATA[i]);
206             check(i);
207         }
208     }
209 
210     @Test
testUnsignedByte()211     public void testUnsignedByte() {
212 
213         final int[] DATA = {
214             0, 1, 0x7F, 0xFF
215         };
216         for (int i = 0; i < DATA.length; i += 1) {
217             out.writeUnsignedByte(DATA[i]);
218             check(i);
219         }
220     }
221 
222     @Test
testUnsignedShort()223     public void testUnsignedShort() {
224 
225         final int[] DATA = {
226             0, 1, 0xFE, 0xFF, 0x800, 0x7FFF, 0xFFFF
227         };
228         for (int i = 0; i < DATA.length; i += 1) {
229             out.writeUnsignedShort(DATA[i]);
230             check(i);
231         }
232     }
233 
234     @Test
testUnsignedInt()235     public void testUnsignedInt() {
236 
237         final long[] DATA = {
238             0, 1, 0xFE, 0xFF, 0x800, 0x7FFF, 0xFFFF, 0x80000,
239             0x7FFFFFFF, 0x80000000, 0xFFFFFFFF
240         };
241         for (int i = 0; i < DATA.length; i += 1) {
242             out.writeUnsignedInt(DATA[i]);
243             check(i);
244         }
245     }
246 
247     @Test
testByte()248     public void testByte() {
249 
250         final byte[] DATA = {
251             Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
252             -1, 0, 1,
253             Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
254         };
255         for (int i = 0; i < DATA.length; i += 1) {
256             out.writeByte(DATA[i]);
257             check(i);
258         }
259     }
260 
261     @Test
testShort()262     public void testShort() {
263 
264         final short[] DATA = {
265             Short.MIN_VALUE, Short.MIN_VALUE + 1,
266             Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
267             -1, 0, 1,
268             Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
269             Short.MAX_VALUE - 1, Short.MAX_VALUE,
270         };
271         for (int i = 0; i < DATA.length; i += 1) {
272             out.writeShort(DATA[i]);
273             check(i);
274         }
275     }
276 
277     @Test
testInt()278     public void testInt() {
279 
280         final int[] DATA = {
281             Integer.MIN_VALUE, Integer.MIN_VALUE + 1,
282             Short.MIN_VALUE, Short.MIN_VALUE + 1,
283             Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
284             -1, 0, 1,
285             Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
286             Short.MAX_VALUE - 1, Short.MAX_VALUE,
287             Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
288         };
289         for (int i = 0; i < DATA.length; i += 1) {
290             out.writeInt(DATA[i]);
291             check(i);
292         }
293     }
294 
295     @Test
testLong()296     public void testLong() {
297 
298         final long[] DATA = {
299             Long.MIN_VALUE, Long.MIN_VALUE + 1,
300             Integer.MIN_VALUE, Integer.MIN_VALUE + 1,
301             Short.MIN_VALUE, Short.MIN_VALUE + 1,
302             Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
303             -1, 0, 1,
304             Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
305             Short.MAX_VALUE - 1, Short.MAX_VALUE,
306             Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
307             Long.MAX_VALUE - 1, Long.MAX_VALUE,
308         };
309         for (int i = 0; i < DATA.length; i += 1) {
310             out.writeLong(DATA[i]);
311             check(i);
312         }
313     }
314 
315     @Test
testFloat()316     public void testFloat() {
317 
318         // Only positive floats and doubles are ordered deterministically
319 
320         final float[] DATA = {
321             0, Float.MIN_VALUE, 2 * Float.MIN_VALUE,
322             (float) 0.01, (float) 0.02, (float) 0.99,
323             1, (float) 1.01, (float) 1.02, (float) 1.99,
324             Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
325             Short.MAX_VALUE - 1, Short.MAX_VALUE,
326             Integer.MAX_VALUE,
327             Long.MAX_VALUE / 2, Long.MAX_VALUE,
328             Float.MAX_VALUE,
329             Float.POSITIVE_INFINITY,
330             Float.NaN,
331         };
332         for (int i = 0; i < DATA.length; i += 1) {
333             out.writeFloat(DATA[i]);
334             check(i);
335         }
336     }
337 
338     @Test
testDouble()339     public void testDouble() {
340 
341         // Only positive floats and doubles are ordered deterministically
342 
343         final double[] DATA = {
344             0, Double.MIN_VALUE, 2 * Double.MIN_VALUE,
345             0.001, 0.002, 0.999,
346             1, 1.001, 1.002, 1.999,
347             Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
348             Short.MAX_VALUE - 1, Short.MAX_VALUE,
349             Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
350             Long.MAX_VALUE / 2, Long.MAX_VALUE,
351             Float.MAX_VALUE, Double.MAX_VALUE,
352             Double.POSITIVE_INFINITY,
353             Double.NaN,
354         };
355         for (int i = 0; i < DATA.length; i += 1) {
356             out.writeDouble(DATA[i]);
357             check(i);
358         }
359     }
360 
361     @Test
testSortedFloat()362     public void testSortedFloat() {
363 
364         final float[] DATA = {
365             Float.NEGATIVE_INFINITY,
366             (- Float.MAX_VALUE),
367             Long.MIN_VALUE,
368             Long.MIN_VALUE / 2,
369             Integer.MIN_VALUE,
370             Short.MIN_VALUE,
371             Short.MIN_VALUE + 1,
372             Byte.MIN_VALUE,
373             Byte.MIN_VALUE + 1,
374             (float) -1.99,
375             (float) -1.02,
376             (float) -1.01,
377             -1,
378             (float) -0.99,
379             (float) -0.02,
380             (float) -0.01,
381             2 * (- Float.MIN_VALUE),
382             (- Float.MIN_VALUE),
383             0,
384             Float.MIN_VALUE,
385             2 * Float.MIN_VALUE,
386             (float) 0.01,
387             (float) 0.02,
388             (float) 0.99,
389             1,
390             (float) 1.01,
391             (float) 1.02,
392             (float) 1.99,
393             Byte.MAX_VALUE - 1,
394             Byte.MAX_VALUE,
395             Short.MAX_VALUE - 1,
396             Short.MAX_VALUE,
397             Integer.MAX_VALUE,
398             Long.MAX_VALUE / 2,
399             Long.MAX_VALUE,
400             Float.MAX_VALUE,
401             Float.POSITIVE_INFINITY,
402             Float.NaN,
403         };
404         for (int i = 0; i < DATA.length; i += 1) {
405             out.writeSortedFloat(DATA[i]);
406             check(i);
407         }
408     }
409 
410     @Test
testSortedDouble()411     public void testSortedDouble() {
412 
413         final double[] DATA = {
414             Double.NEGATIVE_INFINITY,
415             (- Double.MAX_VALUE),
416             (- Float.MAX_VALUE),
417             Long.MIN_VALUE,
418             Long.MIN_VALUE / 2,
419             Integer.MIN_VALUE,
420             Short.MIN_VALUE,
421             Short.MIN_VALUE + 1,
422             Byte.MIN_VALUE,
423             Byte.MIN_VALUE + 1,
424             -1.999,
425             -1.002,
426             -1.001,
427             -1,
428             -0.999,
429             -0.002,
430             -0.001,
431             2 * (- Double.MIN_VALUE),
432             (- Double.MIN_VALUE),
433             0,
434             Double.MIN_VALUE,
435             2 * Double.MIN_VALUE,
436             0.001,
437             0.002,
438             0.999,
439             1,
440             1.001,
441             1.002,
442             1.999,
443             Byte.MAX_VALUE - 1,
444             Byte.MAX_VALUE,
445             Short.MAX_VALUE - 1,
446             Short.MAX_VALUE,
447             Integer.MAX_VALUE - 1,
448             Integer.MAX_VALUE,
449             Long.MAX_VALUE / 2,
450             Long.MAX_VALUE,
451             Float.MAX_VALUE,
452             Double.MAX_VALUE,
453             Double.POSITIVE_INFINITY,
454             Double.NaN,
455         };
456         for (int i = 0; i < DATA.length; i += 1) {
457             out.writeSortedDouble(DATA[i]);
458             check(i);
459         }
460     }
461 
462     @Test
testPackedIntAndLong()463     public void testPackedIntAndLong() {
464         /* Only packed int/long values from 0 to 630 are ordered correctly */
465         for (int i = 0; i <= 630; i += 1) {
466             out.writePackedInt(i);
467             check(i);
468         }
469         reset();
470         for (int i = 0; i <= 630; i += 1) {
471             out.writePackedLong(i);
472             check(i);
473         }
474     }
475 
476     @Test
testSortedPackedInt()477     public void testSortedPackedInt() {
478         final int[] DATA = {
479             Integer.MIN_VALUE, Integer.MIN_VALUE + 1,
480             Short.MIN_VALUE, Short.MIN_VALUE + 1,
481             Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
482             -1, 0, 1,
483             Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
484             Short.MAX_VALUE - 1, Short.MAX_VALUE,
485             Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
486         };
487         for (int i = 0; i < DATA.length; i += 1) {
488             out.writeSortedPackedInt(DATA[i]);
489             check(i);
490         }
491     }
492 
493     @Test
testSortedPackedLong()494     public void testSortedPackedLong() {
495         final long[] DATA = {
496             Long.MIN_VALUE, Long.MIN_VALUE + 1,
497             Integer.MIN_VALUE, Integer.MIN_VALUE + 1,
498             Short.MIN_VALUE, Short.MIN_VALUE + 1,
499             Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
500             -1, 0, 1,
501             Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
502             Short.MAX_VALUE - 1, Short.MAX_VALUE,
503             Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
504             Long.MAX_VALUE - 1, Long.MAX_VALUE,
505         };
506         for (int i = 0; i < DATA.length; i += 1) {
507             out.writeSortedPackedLong(DATA[i]);
508             check(i);
509         }
510     }
511 
512     @Test
testBigInteger()513     public void testBigInteger() {
514         final BigInteger[] DATA = {
515             new BigInteger("-1111111111111111111111111"),
516             new BigInteger("-11111111111111111111"),
517             BigInteger.valueOf(Long.MIN_VALUE),
518             BigInteger.valueOf(Long.MIN_VALUE + 1),
519             BigInteger.valueOf(Integer.MIN_VALUE),
520             BigInteger.valueOf(Integer.MIN_VALUE + 1),
521             BigInteger.valueOf(Short.MIN_VALUE),
522             BigInteger.valueOf(Short.MIN_VALUE + 1),
523             BigInteger.valueOf(Byte.MIN_VALUE),
524             BigInteger.valueOf(Byte.MIN_VALUE + 1),
525             BigInteger.valueOf(-1),
526             BigInteger.ZERO, BigInteger.ONE,
527             BigInteger.valueOf(Byte.MAX_VALUE - 1),
528             BigInteger.valueOf(Byte.MAX_VALUE),
529             BigInteger.valueOf(Short.MAX_VALUE - 1),
530             BigInteger.valueOf(Short.MAX_VALUE),
531             BigInteger.valueOf(Integer.MAX_VALUE - 1),
532             BigInteger.valueOf(Integer.MAX_VALUE),
533             BigInteger.valueOf(Long.MAX_VALUE - 1),
534             BigInteger.valueOf(Long.MAX_VALUE),
535             new BigInteger("11111111111111111111"),
536             new BigInteger("1111111111111111111111111"),
537         };
538         for (int i = 0; i < DATA.length; i += 1) {
539             out.writeBigInteger(DATA[i]);
540             check(i);
541         }
542     }
543 
544     @Test
testSortedBigDecimal()545     public void testSortedBigDecimal() {
546         final BigDecimal[] DATA = {
547             new BigDecimal(BigInteger.valueOf(Long.MIN_VALUE),
548                            Short.MIN_VALUE),
549             new BigDecimal("-9999999999999999999.9999999999999999999"),
550             new BigDecimal("-123456789.123456789"),
551             new BigDecimal("-0.9999999999999999999999999999999999999"),
552             new BigDecimal("-123456789.123456789E-700"),
553             new BigDecimal("-123456789.123456789E-6700"),
554             new BigDecimal(BigInteger.valueOf(Long.MIN_VALUE),
555                            Short.MAX_VALUE),
556             new BigDecimal("0.0"),
557             new BigDecimal(BigInteger.valueOf(Long.MAX_VALUE),
558                            Short.MAX_VALUE),
559             new BigDecimal("0.9999999999999999999999999999999999999"),
560             new BigDecimal("123456789.123456789"),
561             new BigDecimal("9999999999999999999.9999999999999999999"),
562             new BigDecimal("123456789.123456789E700"),
563             new BigDecimal("123456789.123456789E6700"),
564             new BigDecimal(BigInteger.valueOf(Long.MAX_VALUE),
565                            Short.MIN_VALUE),
566         };
567         for (int i = 0; i < DATA.length; i += 1) {
568             out.writeSortedBigDecimal(DATA[i]);
569             check(i);
570         }
571     }
572 }
573