001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.util; 019 020import static org.junit.Assert.assertArrayEquals; 021import static org.junit.Assert.assertEquals; 022import static org.junit.Assert.assertTrue; 023import static org.junit.Assert.fail; 024 025import java.math.BigDecimal; 026import java.util.Arrays; 027import java.util.Collections; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.testclassification.MiscTests; 030import org.apache.hadoop.hbase.testclassification.SmallTests; 031import org.junit.ClassRule; 032import org.junit.Test; 033import org.junit.experimental.categories.Category; 034 035@Category({MiscTests.class, SmallTests.class}) 036public class TestOrderedBytes { 037 038 @ClassRule 039 public static final HBaseClassTestRule CLASS_RULE = 040 HBaseClassTestRule.forClass(TestOrderedBytes.class); 041 042 // integer constants for testing Numeric code paths 043 static final Long[] I_VALS = 044 { 0L, 1L, 10L, 99L, 100L, 1234L, 9999L, 10000L, 10001L, 12345L, 123450L, Long.MAX_VALUE, 045 -1L, -10L, -99L, -100L, -123L, -999L, -10000L, -10001L, -12345L, -123450L, Long.MIN_VALUE }; 046 static final int[] I_LENGTHS = 047 { 1, 2, 2, 2, 2, 3, 3, 2, 4, 4, 4, 11, 2, 2, 2, 2, 3, 3, 2, 4, 4, 4, 11 }; 048 049 // real constants for testing Numeric code paths 050 static final Double[] D_VALS = 051 { 0.0, 0.00123, 0.0123, 0.123, 1.0, 10.0, 12.345, 99.0, 99.01, 99.0001, 100.0, 100.01, 052 100.1, 1234.0, 1234.5, 9999.0, 9999.000001, 9999.000009, 9999.00001, 9999.00009, 053 9999.000099, 9999.0001, 9999.001, 9999.01, 9999.1, 10000.0, 10001.0, 12345.0, 123450.0, 054 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NaN, Double.MAX_VALUE, 055 -0.00123, -0.0123, -0.123, -1.0, -10.0, -12.345, -99.0, -99.01, -99.0001, -100.0, -100.01, 056 -100.1, -1234.0, -1234.5, -9999.0, -9999.000001, -9999.000009, -9999.00001, -9999.00009, 057 -9999.000099, -9999.0001, -9999.001, -9999.01, -9999.1, -10000.0, -10001.0, -12345.0, 058 -123450.0 }; 059 static final int[] D_LENGTHS = 060 { 1, 4, 4, 4, 2, 2, 4, 2, 3, 4, 2, 4, 061 4, 3, 4, 3, 6, 6, 6, 6, 062 6, 5, 5, 4, 4, 2, 4, 4, 4, 063 1, 1, 1, 11, 064 4, 4, 4, 2, 2, 4, 2, 3, 4, 2, 4, 065 4, 3, 4, 3, 6, 6, 6, 6, 066 6, 5, 5, 4, 4, 2, 4, 4, 067 4 }; 068 069 // fill in other gaps in Numeric code paths 070 static final BigDecimal[] BD_VALS = 071 { null, BigDecimal.valueOf(Long.MAX_VALUE), BigDecimal.valueOf(Long.MIN_VALUE), 072 BigDecimal.valueOf(Double.MAX_VALUE), BigDecimal.valueOf(Double.MIN_VALUE), 073 BigDecimal.valueOf(Long.MAX_VALUE).multiply(BigDecimal.valueOf(100)) }; 074 static final int[] BD_LENGTHS = 075 { 1, 11, 11, 11, 4, 12 }; 076 077 /* 078 * This is the smallest difference between two doubles in D_VALS 079 */ 080 static final double MIN_EPSILON = 0.000001; 081 082 /** 083 * Expected lengths of equivalent values should match 084 */ 085 @Test 086 public void testVerifyTestIntegrity() { 087 for (int i = 0; i < I_VALS.length; i++) { 088 for (int d = 0; d < D_VALS.length; d++) { 089 if (Math.abs(I_VALS[i] - D_VALS[d]) < MIN_EPSILON) { 090 assertEquals( 091 "Test inconsistency detected: expected lengths for " + I_VALS[i] + " do not match.", 092 I_LENGTHS[i], D_LENGTHS[d]); 093 } 094 } 095 } 096 } 097 098 /** 099 * Tests the variable uint64 encoding. 100 * <p> 101 * Building sqlite4 with -DVARINT_TOOL provides this reference:<br /> 102 * <code>$ ./varint_tool 240 2287 67823 16777215 4294967295 1099511627775 103 * 281474976710655 72057594037927935 18446744073709551615<br /> 104 * 240 = f0<br /> 105 * 2287 = f8ff<br /> 106 * 67823 = f9ffff<br /> 107 * 16777215 = faffffff<br /> 108 * 4294967295 = fbffffffff<br /> 109 * 1099511627775 = fcffffffffff<br /> 110 * 281474976710655 = fdffffffffffff<br /> 111 * 72057594037927935 = feffffffffffffff<br /> 112 * 9223372036854775807 = ff7fffffffffffffff (Long.MAX_VAL)<br /> 113 * 9223372036854775808 = ff8000000000000000 (Long.MIN_VAL)<br /> 114 * 18446744073709551615 = ffffffffffffffffff<br /></code> 115 * </p> 116 */ 117 @Test 118 public void testVaruint64Boundaries() { 119 long[] vals = { 120 239L, 240L, 2286L, 2287L, 67822L, 67823L, 16777214L, 16777215L, 4294967294L, 4294967295L, 121 1099511627774L, 1099511627775L, 281474976710654L, 281474976710655L, 72057594037927934L, 122 72057594037927935L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Long.MIN_VALUE + 1, 123 Long.MIN_VALUE, -2L, -1L 124 }; 125 int[] lens = { 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9 }; 126 assertEquals("Broken test!", vals.length, lens.length); 127 128 /* 129 * assert encoded values match decoded values. encode into target buffer 130 * starting at an offset to detect over/underflow conditions. 131 */ 132 for (boolean comp : new boolean[] { true, false }) { 133 for (int i = 0; i < vals.length; i++) { 134 // allocate a buffer 2-bytes larger than necessary and place our range over the center. 135 byte[] a = new byte[lens[i] + 2]; 136 PositionedByteRange buf = new SimplePositionedMutableByteRange(a, 1, lens[i]); 137 138 // verify encode 139 assertEquals("Surprising return value.", 140 lens[i], OrderedBytes.putVaruint64(buf, vals[i], comp)); 141 assertEquals("Surprising serialized length.", lens[i], buf.getPosition()); 142 assertEquals("Buffer underflow.", 0, a[0]); 143 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 144 145 // verify skip 146 buf.setPosition(0); 147 assertEquals("Surprising return value.", 148 lens[i], OrderedBytes.skipVaruint64(buf, comp)); 149 assertEquals("Did not skip enough bytes.", lens[i], buf.getPosition()); 150 151 // verify decode 152 buf.setPosition(0); 153 assertEquals("Deserialization failed.", vals[i], OrderedBytes.getVaruint64(buf, comp)); 154 assertEquals("Did not consume enough bytes.", lens[i], buf.getPosition()); 155 } 156 } 157 } 158 159 /** 160 * Test integer encoding. Example input values come from reference wiki 161 * page. 162 */ 163 @Test 164 public void testNumericInt() { 165 /* 166 * assert encoded values match decoded values. encode into target buffer 167 * starting at an offset to detect over/underflow conditions. 168 */ 169 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 170 for (int i = 0; i < I_VALS.length; i++) { 171 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 172 byte[] a = new byte[I_LENGTHS[i] + 3]; 173 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, I_LENGTHS[i] + 1); 174 buf1.setPosition(1); 175 176 // verify encode 177 assertEquals("Surprising return value.", 178 I_LENGTHS[i], OrderedBytes.encodeNumeric(buf1, I_VALS[i], ord)); 179 assertEquals("Broken test: serialization did not consume entire buffer.", 180 buf1.getLength(), buf1.getPosition()); 181 assertEquals("Surprising serialized length.", I_LENGTHS[i], buf1.getPosition() - 1); 182 assertEquals("Buffer underflow.", 0, a[0]); 183 assertEquals("Buffer underflow.", 0, a[1]); 184 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 185 186 // verify skip 187 buf1.setPosition(1); 188 assertEquals("Surprising return value.", I_LENGTHS[i], OrderedBytes.skip(buf1)); 189 assertEquals("Did not skip enough bytes.", I_LENGTHS[i], buf1.getPosition() - 1); 190 191 // verify decode 192 buf1.setPosition(1); 193 assertEquals("Deserialization failed.", 194 I_VALS[i].longValue(), OrderedBytes.decodeNumericAsLong(buf1)); 195 assertEquals("Did not consume enough bytes.", I_LENGTHS[i], buf1.getPosition() - 1); 196 } 197 } 198 199 /* 200 * assert natural sort order is preserved by the codec. 201 */ 202 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 203 byte[][] encoded = new byte[I_VALS.length][]; 204 PositionedByteRange pbr = new SimplePositionedMutableByteRange(); 205 for (int i = 0; i < I_VALS.length; i++) { 206 encoded[i] = new byte[I_LENGTHS[i]]; 207 OrderedBytes.encodeNumeric(pbr.set(encoded[i]), I_VALS[i], ord); 208 } 209 210 Arrays.sort(encoded, Bytes.BYTES_COMPARATOR); 211 Long[] sortedVals = Arrays.copyOf(I_VALS, I_VALS.length); 212 213 if (ord == Order.ASCENDING) { 214 Arrays.sort(sortedVals); 215 } else { 216 Arrays.sort(sortedVals, Collections.reverseOrder()); 217 } 218 219 for (int i = 0; i < sortedVals.length; i++) { 220 pbr.set(encoded[i]); 221 long decoded = OrderedBytes.decodeNumericAsLong(pbr); 222 assertEquals( 223 String.format( 224 "Encoded representations do not preserve natural order: <%s>, <%s>, %s", 225 sortedVals[i], decoded, ord), 226 sortedVals[i].longValue(), decoded); 227 } 228 } 229 } 230 231 /** 232 * Test real encoding. Example input values come from reference wiki page. 233 */ 234 @Test 235 public void testNumericReal() { 236 /* 237 * assert encoded values match decoded values. encode into target buffer 238 * starting at an offset to detect over/underflow conditions. 239 */ 240 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 241 for (int i = 0; i < D_VALS.length; i++) { 242 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 243 byte[] a = new byte[D_LENGTHS[i] + 3]; 244 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, D_LENGTHS[i] + 1); 245 buf1.setPosition(1); 246 247 // verify encode 248 assertEquals("Surprising return value.", 249 D_LENGTHS[i], OrderedBytes.encodeNumeric(buf1, D_VALS[i], ord)); 250 assertEquals("Broken test: serialization did not consume entire buffer.", 251 buf1.getLength(), buf1.getPosition()); 252 assertEquals("Surprising serialized length.", D_LENGTHS[i], buf1.getPosition() - 1); 253 assertEquals("Buffer underflow.", 0, a[0]); 254 assertEquals("Buffer underflow.", 0, a[1]); 255 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 256 257 // verify skip 258 buf1.setPosition(1); 259 assertEquals("Surprising return value.", D_LENGTHS[i], OrderedBytes.skip(buf1)); 260 assertEquals("Did not skip enough bytes.", D_LENGTHS[i], buf1.getPosition() - 1); 261 262 // verify decode 263 buf1.setPosition(1); 264 assertEquals("Deserialization failed.", D_VALS[i], 265 OrderedBytes.decodeNumericAsDouble(buf1), MIN_EPSILON); 266 assertEquals("Did not consume enough bytes.", D_LENGTHS[i], buf1.getPosition() - 1); 267 } 268 } 269 270 /* 271 * assert natural sort order is preserved by the codec. 272 */ 273 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 274 byte[][] encoded = new byte[D_VALS.length][]; 275 PositionedByteRange pbr = new SimplePositionedMutableByteRange(); 276 for (int i = 0; i < D_VALS.length; i++) { 277 encoded[i] = new byte[D_LENGTHS[i]]; 278 OrderedBytes.encodeNumeric(pbr.set(encoded[i]), D_VALS[i], ord); 279 } 280 281 Arrays.sort(encoded, Bytes.BYTES_COMPARATOR); 282 Double[] sortedVals = Arrays.copyOf(D_VALS, D_VALS.length); 283 284 if (ord == Order.ASCENDING) { 285 Arrays.sort(sortedVals); 286 } else { 287 Arrays.sort(sortedVals, Collections.reverseOrder()); 288 } 289 290 for (int i = 0; i < sortedVals.length; i++) { 291 pbr.set(encoded[i]); 292 double decoded = OrderedBytes.decodeNumericAsDouble(pbr); 293 assertEquals( 294 String.format( 295 "Encoded representations do not preserve natural order: <%s>, <%s>, %s", 296 sortedVals[i], decoded, ord), sortedVals[i], decoded, MIN_EPSILON); 297 } 298 } 299 } 300 301 /** 302 * Fill gaps in Numeric encoding testing. 303 */ 304 @Test 305 public void testNumericOther() { 306 /* 307 * assert encoded values match decoded values. encode into target buffer 308 * starting at an offset to detect over/underflow conditions. 309 */ 310 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 311 for (int i = 0; i < BD_VALS.length; i++) { 312 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 313 byte[] a = new byte[BD_LENGTHS[i] + 3]; 314 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, BD_LENGTHS[i] + 1); 315 buf1.setPosition(1); 316 317 // verify encode 318 assertEquals("Surprising return value.", 319 BD_LENGTHS[i], OrderedBytes.encodeNumeric(buf1, BD_VALS[i], ord)); 320 assertEquals("Broken test: serialization did not consume entire buffer.", 321 buf1.getLength(), buf1.getPosition()); 322 assertEquals("Surprising serialized length.", BD_LENGTHS[i], buf1.getPosition() - 1); 323 assertEquals("Buffer underflow.", 0, a[0]); 324 assertEquals("Buffer underflow.", 0, a[1]); 325 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 326 327 // verify skip 328 buf1.setPosition(1); 329 assertEquals("Surprising return value.", BD_LENGTHS[i], OrderedBytes.skip(buf1)); 330 assertEquals("Did not skip enough bytes.", BD_LENGTHS[i], buf1.getPosition() - 1); 331 332 // verify decode 333 buf1.setPosition(1); 334 BigDecimal decoded = OrderedBytes.decodeNumericAsBigDecimal(buf1); 335 if (null == BD_VALS[i]) { 336 assertEquals(BD_VALS[i], decoded); 337 } else { 338 assertEquals("Deserialization failed.", 0, BD_VALS[i].compareTo(decoded)); 339 } 340 assertEquals("Did not consume enough bytes.", BD_LENGTHS[i], buf1.getPosition() - 1); 341 } 342 } 343 } 344 345 /** 346 * Verify Real and Int encodings are compatible. 347 */ 348 @Test 349 public void testNumericIntRealCompatibility() { 350 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 351 for (int i = 0; i < I_VALS.length; i++) { 352 // verify primitives 353 PositionedByteRange pbri = new SimplePositionedMutableByteRange(I_LENGTHS[i]); 354 PositionedByteRange pbrr = new SimplePositionedMutableByteRange(I_LENGTHS[i]); 355 OrderedBytes.encodeNumeric(pbri, I_VALS[i], ord); 356 OrderedBytes.encodeNumeric(pbrr, I_VALS[i], ord); 357 assertArrayEquals("Integer and real encodings differ.", pbri.getBytes(), pbrr.getBytes()); 358 pbri.setPosition(0); 359 pbrr.setPosition(0); 360 assertEquals((long) I_VALS[i], OrderedBytes.decodeNumericAsLong(pbri)); 361 assertEquals((long) I_VALS[i], (long) OrderedBytes.decodeNumericAsDouble(pbrr)); 362 363 // verify BigDecimal for Real encoding 364 BigDecimal bd = BigDecimal.valueOf(I_VALS[i]); 365 PositionedByteRange pbrbd = new SimplePositionedMutableByteRange(I_LENGTHS[i]); 366 OrderedBytes.encodeNumeric(pbrbd, bd, ord); 367 assertArrayEquals("Integer and BigDecimal encodings differ.", 368 pbri.getBytes(), pbrbd.getBytes()); 369 pbri.setPosition(0); 370 assertEquals("Value not preserved when decoding as Long", 371 0, bd.compareTo(BigDecimal.valueOf(OrderedBytes.decodeNumericAsLong(pbri)))); 372 } 373 } 374 } 375 376 /** 377 * Test int8 encoding. 378 */ 379 @Test 380 public void testInt8() { 381 Byte[] vals = 382 { Byte.MIN_VALUE, Byte.MIN_VALUE / 2, 0, Byte.MAX_VALUE / 2, Byte.MAX_VALUE }; 383 384 /* 385 * assert encoded values match decoded values. encode into target buffer 386 * starting at an offset to detect over/underflow conditions. 387 */ 388 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 389 for (Byte val : vals) { 390 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 391 byte[] a = new byte[2 + 3]; 392 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, 2 + 1); 393 buf1.setPosition(1); 394 395 // verify encode 396 assertEquals("Surprising return value.", 2, OrderedBytes.encodeInt8(buf1, val, ord)); 397 assertEquals("Broken test: serialization did not consume entire buffer.", buf1.getLength(), 398 buf1.getPosition()); 399 assertEquals("Surprising serialized length.", 2, buf1.getPosition() - 1); 400 assertEquals("Buffer underflow.", 0, a[0]); 401 assertEquals("Buffer underflow.", 0, a[1]); 402 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 403 404 // verify skip 405 buf1.setPosition(1); 406 assertEquals("Surprising return value.", 2, OrderedBytes.skip(buf1)); 407 assertEquals("Did not skip enough bytes.", 2, buf1.getPosition() - 1); 408 409 // verify decode 410 buf1.setPosition(1); 411 assertEquals("Deserialization failed.", val.byteValue(), OrderedBytes.decodeInt8(buf1)); 412 assertEquals("Did not consume enough bytes.", 2, buf1.getPosition() - 1); 413 } 414 } 415 416 /* 417 * assert natural sort order is preserved by the codec. 418 */ 419 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 420 byte[][] encoded = new byte[vals.length][2]; 421 PositionedByteRange pbr = new SimplePositionedMutableByteRange(); 422 for (int i = 0; i < vals.length; i++) { 423 OrderedBytes.encodeInt8(pbr.set(encoded[i]), vals[i], ord); 424 } 425 426 Arrays.sort(encoded, Bytes.BYTES_COMPARATOR); 427 Byte[] sortedVals = Arrays.copyOf(vals, vals.length); 428 429 if (ord == Order.ASCENDING) { 430 Arrays.sort(sortedVals); 431 } else { 432 Arrays.sort(sortedVals, Collections.reverseOrder()); 433 } 434 435 for (int i = 0; i < sortedVals.length; i++) { 436 int decoded = OrderedBytes.decodeInt8(pbr.set(encoded[i])); 437 assertEquals( 438 String.format( 439 "Encoded representations do not preserve natural order: <%s>, <%s>, %s", 440 sortedVals[i], decoded, ord), 441 sortedVals[i].byteValue(), decoded); 442 } 443 } 444 } 445 446 /** 447 * Test int16 encoding. 448 */ 449 @Test 450 public void testInt16() { 451 Short[] vals = 452 { Short.MIN_VALUE, Short.MIN_VALUE / 2, 0, Short.MAX_VALUE / 2, Short.MAX_VALUE }; 453 454 /* 455 * assert encoded values match decoded values. encode into target buffer 456 * starting at an offset to detect over/underflow conditions. 457 */ 458 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 459 for (Short val : vals) { 460 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 461 byte[] a = new byte[3 + 3]; 462 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, 3 + 1); 463 buf1.setPosition(1); 464 465 // verify encode 466 assertEquals("Surprising return value.", 3, OrderedBytes.encodeInt16(buf1, val, ord)); 467 assertEquals("Broken test: serialization did not consume entire buffer.", buf1.getLength(), 468 buf1.getPosition()); 469 assertEquals("Surprising serialized length.", 3, buf1.getPosition() - 1); 470 assertEquals("Buffer underflow.", 0, a[0]); 471 assertEquals("Buffer underflow.", 0, a[1]); 472 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 473 474 // verify skip 475 buf1.setPosition(1); 476 assertEquals("Surprising return value.", 3, OrderedBytes.skip(buf1)); 477 assertEquals("Did not skip enough bytes.", 3, buf1.getPosition() - 1); 478 479 // verify decode 480 buf1.setPosition(1); 481 assertEquals("Deserialization failed.", val.shortValue(), OrderedBytes.decodeInt16(buf1)); 482 assertEquals("Did not consume enough bytes.", 3, buf1.getPosition() - 1); 483 } 484 } 485 486 /* 487 * assert natural sort order is preserved by the codec. 488 */ 489 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 490 byte[][] encoded = new byte[vals.length][3]; 491 PositionedByteRange pbr = new SimplePositionedMutableByteRange(); 492 for (int i = 0; i < vals.length; i++) { 493 OrderedBytes.encodeInt16(pbr.set(encoded[i]), vals[i], ord); 494 } 495 496 Arrays.sort(encoded, Bytes.BYTES_COMPARATOR); 497 Short[] sortedVals = Arrays.copyOf(vals, vals.length); 498 499 if (ord == Order.ASCENDING) { 500 Arrays.sort(sortedVals); 501 } else { 502 Arrays.sort(sortedVals, Collections.reverseOrder()); 503 } 504 505 for (int i = 0; i < sortedVals.length; i++) { 506 int decoded = OrderedBytes.decodeInt16(pbr.set(encoded[i])); 507 assertEquals( 508 String.format( 509 "Encoded representations do not preserve natural order: <%s>, <%s>, %s", 510 sortedVals[i], decoded, ord), 511 sortedVals[i].shortValue(), decoded); 512 } 513 } 514 } 515 516 /** 517 * Test int32 encoding. 518 */ 519 @Test 520 public void testInt32() { 521 Integer[] vals = 522 { Integer.MIN_VALUE, Integer.MIN_VALUE / 2, 0, Integer.MAX_VALUE / 2, Integer.MAX_VALUE }; 523 524 /* 525 * assert encoded values match decoded values. encode into target buffer 526 * starting at an offset to detect over/underflow conditions. 527 */ 528 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 529 for (Integer val : vals) { 530 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 531 byte[] a = new byte[5 + 3]; 532 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, 5 + 1); 533 buf1.setPosition(1); 534 535 // verify encode 536 assertEquals("Surprising return value.", 5, OrderedBytes.encodeInt32(buf1, val, ord)); 537 assertEquals("Broken test: serialization did not consume entire buffer.", buf1.getLength(), 538 buf1.getPosition()); 539 assertEquals("Surprising serialized length.", 5, buf1.getPosition() - 1); 540 assertEquals("Buffer underflow.", 0, a[0]); 541 assertEquals("Buffer underflow.", 0, a[1]); 542 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 543 544 // verify skip 545 buf1.setPosition(1); 546 assertEquals("Surprising return value.", 5, OrderedBytes.skip(buf1)); 547 assertEquals("Did not skip enough bytes.", 5, buf1.getPosition() - 1); 548 549 // verify decode 550 buf1.setPosition(1); 551 assertEquals("Deserialization failed.", val.intValue(), OrderedBytes.decodeInt32(buf1)); 552 assertEquals("Did not consume enough bytes.", 5, buf1.getPosition() - 1); 553 } 554 } 555 556 /* 557 * assert natural sort order is preserved by the codec. 558 */ 559 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 560 byte[][] encoded = new byte[vals.length][5]; 561 PositionedByteRange pbr = new SimplePositionedMutableByteRange(); 562 for (int i = 0; i < vals.length; i++) { 563 OrderedBytes.encodeInt32(pbr.set(encoded[i]), vals[i], ord); 564 } 565 566 Arrays.sort(encoded, Bytes.BYTES_COMPARATOR); 567 Integer[] sortedVals = Arrays.copyOf(vals, vals.length); 568 569 if (ord == Order.ASCENDING) { 570 Arrays.sort(sortedVals); 571 } else { 572 Arrays.sort(sortedVals, Collections.reverseOrder()); 573 } 574 575 for (int i = 0; i < sortedVals.length; i++) { 576 int decoded = OrderedBytes.decodeInt32(pbr.set(encoded[i])); 577 assertEquals( 578 String.format( 579 "Encoded representations do not preserve natural order: <%s>, <%s>, %s", 580 sortedVals[i], decoded, ord), 581 sortedVals[i].intValue(), decoded); 582 } 583 } 584 } 585 586 /** 587 * Test int64 encoding. 588 */ 589 @Test 590 public void testInt64() { 591 Long[] vals = { Long.MIN_VALUE, Long.MIN_VALUE / 2, 0L, Long.MAX_VALUE / 2, Long.MAX_VALUE }; 592 593 /* 594 * assert encoded values match decoded values. encode into target buffer 595 * starting at an offset to detect over/underflow conditions. 596 */ 597 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 598 for (Long val : vals) { 599 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 600 byte[] a = new byte[9 + 3]; 601 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, 9 + 1); 602 buf1.setPosition(1); 603 604 // verify encode 605 assertEquals("Surprising return value.", 9, OrderedBytes.encodeInt64(buf1, val, ord)); 606 assertEquals("Broken test: serialization did not consume entire buffer.", buf1.getLength(), 607 buf1.getPosition()); 608 assertEquals("Surprising serialized length.", 9, buf1.getPosition() - 1); 609 assertEquals("Buffer underflow.", 0, a[0]); 610 assertEquals("Buffer underflow.", 0, a[1]); 611 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 612 613 // verify skip 614 buf1.setPosition(1); 615 assertEquals("Surprising return value.", 9, OrderedBytes.skip(buf1)); 616 assertEquals("Did not skip enough bytes.", 9, buf1.getPosition() - 1); 617 618 // verify decode 619 buf1.setPosition(1); 620 assertEquals("Deserialization failed.", val.longValue(), OrderedBytes.decodeInt64(buf1)); 621 assertEquals("Did not consume enough bytes.", 9, buf1.getPosition() - 1); 622 } 623 } 624 625 /* 626 * assert natural sort order is preserved by the codec. 627 */ 628 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 629 byte[][] encoded = new byte[vals.length][9]; 630 PositionedByteRange pbr = new SimplePositionedMutableByteRange(); 631 for (int i = 0; i < vals.length; i++) { 632 OrderedBytes.encodeInt64(pbr.set(encoded[i]), vals[i], ord); 633 } 634 635 Arrays.sort(encoded, Bytes.BYTES_COMPARATOR); 636 Long[] sortedVals = Arrays.copyOf(vals, vals.length); 637 638 if (ord == Order.ASCENDING) { 639 Arrays.sort(sortedVals); 640 } else { 641 Arrays.sort(sortedVals, Collections.reverseOrder()); 642 } 643 644 for (int i = 0; i < sortedVals.length; i++) { 645 long decoded = OrderedBytes.decodeInt64(pbr.set(encoded[i])); 646 assertEquals( 647 String.format( 648 "Encoded representations do not preserve natural order: <%s>, <%s>, %s", 649 sortedVals[i], decoded, ord), 650 sortedVals[i].longValue(), decoded); 651 } 652 } 653 } 654 655 /** 656 * Test float32 encoding. 657 */ 658 @Test 659 public void testFloat32() { 660 Float[] vals = 661 { Float.MIN_VALUE, Float.MIN_VALUE + 1.0f, 0.0f, Float.MAX_VALUE / 2.0f, Float.MAX_VALUE }; 662 663 /* 664 * assert encoded values match decoded values. encode into target buffer 665 * starting at an offset to detect over/underflow conditions. 666 */ 667 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 668 for (Float val : vals) { 669 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 670 byte[] a = new byte[5 + 3]; 671 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, 5 + 1); 672 buf1.setPosition(1); 673 674 // verify encode 675 assertEquals("Surprising return value.", 5, OrderedBytes.encodeFloat32(buf1, val, ord)); 676 assertEquals("Broken test: serialization did not consume entire buffer.", buf1.getLength(), 677 buf1.getPosition()); 678 assertEquals("Surprising serialized length.", 5, buf1.getPosition() - 1); 679 assertEquals("Buffer underflow.", 0, a[0]); 680 assertEquals("Buffer underflow.", 0, a[1]); 681 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 682 683 // verify skip 684 buf1.setPosition(1); 685 assertEquals("Surprising return value.", 5, OrderedBytes.skip(buf1)); 686 assertEquals("Did not skip enough bytes.", 5, buf1.getPosition() - 1); 687 688 // verify decode 689 buf1.setPosition(1); 690 assertEquals("Deserialization failed.", Float.floatToIntBits(val), 691 Float.floatToIntBits(OrderedBytes.decodeFloat32(buf1))); 692 assertEquals("Did not consume enough bytes.", 5, buf1.getPosition() - 1); 693 } 694 } 695 696 /* 697 * assert natural sort order is preserved by the codec. 698 */ 699 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 700 byte[][] encoded = new byte[vals.length][5]; 701 PositionedByteRange pbr = new SimplePositionedMutableByteRange(); 702 for (int i = 0; i < vals.length; i++) { 703 OrderedBytes.encodeFloat32(pbr.set(encoded[i]), vals[i], ord); 704 } 705 706 Arrays.sort(encoded, Bytes.BYTES_COMPARATOR); 707 Float[] sortedVals = Arrays.copyOf(vals, vals.length); 708 709 if (ord == Order.ASCENDING) { 710 Arrays.sort(sortedVals); 711 } else { 712 Arrays.sort(sortedVals, Collections.reverseOrder()); 713 } 714 715 for (int i = 0; i < sortedVals.length; i++) { 716 float decoded = OrderedBytes.decodeFloat32(pbr.set(encoded[i])); 717 assertEquals( 718 String.format( 719 "Encoded representations do not preserve natural order: <%s>, <%s>, %s", 720 sortedVals[i], decoded, ord), 721 Float.floatToIntBits(sortedVals[i]), 722 Float.floatToIntBits(decoded)); 723 } 724 } 725 } 726 727 /** 728 * Test float64 encoding. 729 */ 730 @Test 731 public void testFloat64() { 732 Double[] vals = 733 { Double.MIN_VALUE, Double.MIN_VALUE + 1.0, 0.0, Double.MAX_VALUE / 2.0, Double.MAX_VALUE }; 734 735 /* 736 * assert encoded values match decoded values. encode into target buffer 737 * starting at an offset to detect over/underflow conditions. 738 */ 739 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 740 for (Double val : vals) { 741 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 742 byte[] a = new byte[9 + 3]; 743 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, 9 + 1); 744 buf1.setPosition(1); 745 746 // verify encode 747 assertEquals("Surprising return value.", 9, OrderedBytes.encodeFloat64(buf1, val, ord)); 748 assertEquals("Broken test: serialization did not consume entire buffer.", buf1.getLength(), 749 buf1.getPosition()); 750 assertEquals("Surprising serialized length.", 9, buf1.getPosition() - 1); 751 assertEquals("Buffer underflow.", 0, a[0]); 752 assertEquals("Buffer underflow.", 0, a[1]); 753 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 754 755 // verify skip 756 buf1.setPosition(1); 757 assertEquals("Surprising return value.", 9, OrderedBytes.skip(buf1)); 758 assertEquals("Did not skip enough bytes.", 9, buf1.getPosition() - 1); 759 760 // verify decode 761 buf1.setPosition(1); 762 assertEquals("Deserialization failed.", Double.doubleToLongBits(val), 763 Double.doubleToLongBits(OrderedBytes.decodeFloat64(buf1))); 764 assertEquals("Did not consume enough bytes.", 9, buf1.getPosition() - 1); 765 } 766 } 767 768 /* 769 * assert natural sort order is preserved by the codec. 770 */ 771 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 772 byte[][] encoded = new byte[vals.length][9]; 773 PositionedByteRange pbr = new SimplePositionedMutableByteRange(); 774 for (int i = 0; i < vals.length; i++) { 775 OrderedBytes.encodeFloat64(pbr.set(encoded[i]), vals[i], ord); 776 } 777 778 Arrays.sort(encoded, Bytes.BYTES_COMPARATOR); 779 Double[] sortedVals = Arrays.copyOf(vals, vals.length); 780 781 if (ord == Order.ASCENDING) { 782 Arrays.sort(sortedVals); 783 } else { 784 Arrays.sort(sortedVals, Collections.reverseOrder()); 785 } 786 787 for (int i = 0; i < sortedVals.length; i++) { 788 double decoded = OrderedBytes.decodeFloat64(pbr.set(encoded[i])); 789 assertEquals( 790 String.format( 791 "Encoded representations do not preserve natural order: <%s>, <%s>, %s", 792 sortedVals[i], decoded, ord), 793 Double.doubleToLongBits(sortedVals[i]), 794 Double.doubleToLongBits(decoded)); 795 } 796 } 797 } 798 799 /** 800 * Test string encoding. 801 */ 802 @Test 803 public void testString() { 804 String[] vals = { "foo", "baaaar", "bazz" }; 805 int[] expectedLengths = { 5, 8, 6 }; 806 807 /* 808 * assert encoded values match decoded values. encode into target buffer 809 * starting at an offset to detect over/underflow conditions. 810 */ 811 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 812 for (int i = 0; i < vals.length; i++) { 813 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 814 byte[] a = new byte[expectedLengths[i] + 3]; 815 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, 816 expectedLengths[i] + 1); 817 buf1.setPosition(1); 818 819 // verify encode 820 assertEquals("Surprising return value.", 821 expectedLengths[i], OrderedBytes.encodeString(buf1, vals[i], ord)); 822 assertEquals("Broken test: serialization did not consume entire buffer.", 823 buf1.getLength(), buf1.getPosition()); 824 assertEquals("Surprising serialized length.", expectedLengths[i], buf1.getPosition() - 1); 825 assertEquals("Buffer underflow.", 0, a[0]); 826 assertEquals("Buffer underflow.", 0, a[1]); 827 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 828 829 // verify skip 830 buf1.setPosition(1); 831 assertEquals("Surprising return value.", expectedLengths[i], OrderedBytes.skip(buf1)); 832 assertEquals("Did not skip enough bytes.", expectedLengths[i], buf1.getPosition() - 1); 833 834 // verify decode 835 buf1.setPosition(1); 836 assertEquals("Deserialization failed.", vals[i], OrderedBytes.decodeString(buf1)); 837 assertEquals("Did not consume enough bytes.", expectedLengths[i], buf1.getPosition() - 1); 838 } 839 } 840 841 /* 842 * assert natural sort order is preserved by the codec. 843 */ 844 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 845 byte[][] encoded = new byte[vals.length][]; 846 PositionedByteRange pbr = new SimplePositionedMutableByteRange(); 847 for (int i = 0; i < vals.length; i++) { 848 encoded[i] = new byte[expectedLengths[i]]; 849 OrderedBytes.encodeString(pbr.set(encoded[i]), vals[i], ord); 850 } 851 852 Arrays.sort(encoded, Bytes.BYTES_COMPARATOR); 853 String[] sortedVals = Arrays.copyOf(vals, vals.length); 854 855 if (ord == Order.ASCENDING) { 856 Arrays.sort(sortedVals); 857 } else { 858 Arrays.sort(sortedVals, Collections.reverseOrder()); 859 } 860 861 for (int i = 0; i < sortedVals.length; i++) { 862 pbr.set(encoded[i]); 863 String decoded = OrderedBytes.decodeString(pbr); 864 assertEquals( 865 String.format( 866 "Encoded representations do not preserve natural order: <%s>, <%s>, %s", 867 sortedVals[i], decoded, ord), 868 sortedVals[i], decoded); 869 } 870 } 871 } 872 873 @Test(expected = IllegalArgumentException.class) 874 public void testStringNoNullChars() { 875 PositionedByteRange buff = new SimplePositionedMutableByteRange(3); 876 OrderedBytes.encodeString(buff, "\u0000", Order.ASCENDING); 877 } 878 879 /** 880 * Test length estimation algorithms for BlobVar encoding. Does not cover 881 * 0-length input case properly. 882 */ 883 @Test 884 public void testBlobVarLencodedLength() { 885 int[][] values = { 886 /* decoded length, encoded length 887 * ceil((n bytes * 8 bits/input byte) / 7 bits/encoded byte) + 1 header 888 */ 889 { 1, 3 }, { 2, 4 }, { 3, 5 }, { 4, 6 }, 890 { 5, 7 }, { 6, 8 }, { 7, 9 }, { 8, 11 } 891 }; 892 893 for (int[] pair : values) { 894 assertEquals(pair[1], OrderedBytes.blobVarEncodedLength(pair[0])); 895 assertEquals(pair[0], OrderedBytes.blobVarDecodedLength(pair[1])); 896 } 897 } 898 899 /** 900 * Test BlobVar encoding. 901 */ 902 @Test 903 public void testBlobVar() { 904 byte[][] vals = 905 { Bytes.toBytes(""), 906 Bytes.toBytes("foo"), 907 Bytes.toBytes("foobarbazbub"), 908 { (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, 909 (byte) 0xaa, /* 7 bytes of alternating bits; testing around HBASE-9893 */ }, 910 { (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, 911 (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa }, 912 { (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, 913 (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, 914 (byte) 0xaa, (byte) 0xaa, /* 14 bytes of alternating bits; testing around HBASE-9893 */ }, 915 { (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, 916 (byte) 0x55, /* 7 bytes of alternating bits; testing around HBASE-9893 */ }, 917 { (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, 918 (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55 }, 919 { (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, 920 (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, 921 (byte) 0x55, (byte) 0x55, /* 14 bytes of alternating bits; testing around HBASE-9893 */ }, 922 Bytes.toBytes("1"), 923 Bytes.toBytes("22"), 924 Bytes.toBytes("333"), 925 Bytes.toBytes("4444"), 926 Bytes.toBytes("55555"), 927 Bytes.toBytes("666666"), 928 Bytes.toBytes("7777777"), 929 Bytes.toBytes("88888888") 930 }; 931 932 /* 933 * assert encoded values match decoded values. encode into target buffer 934 * starting at an offset to detect over/underflow conditions. 935 */ 936 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 937 for (byte[] val : vals) { 938 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 939 int expectedLen = OrderedBytes.blobVarEncodedLength(val.length); 940 byte[] a = new byte[expectedLen + 3]; 941 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, expectedLen + 1); 942 buf1.setPosition(1); 943 944 // verify encode 945 assertEquals("Surprising return value.", 946 expectedLen, OrderedBytes.encodeBlobVar(buf1, val, ord)); 947 assertEquals("Broken test: serialization did not consume entire buffer.", 948 buf1.getLength(), buf1.getPosition()); 949 assertEquals("Surprising serialized length.", expectedLen, buf1.getPosition() - 1); 950 assertEquals("Buffer underflow.", 0, a[0]); 951 assertEquals("Buffer underflow.", 0, a[1]); 952 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 953 954 // verify skip 955 buf1.setPosition(1); 956 assertEquals("Surprising return value.", expectedLen, OrderedBytes.skip(buf1)); 957 assertEquals("Did not skip enough bytes.", expectedLen, buf1.getPosition() - 1); 958 959 // verify decode 960 buf1.setPosition(1); 961 assertArrayEquals("Deserialization failed.", val, OrderedBytes.decodeBlobVar(buf1)); 962 assertEquals("Did not consume enough bytes.", expectedLen, buf1.getPosition() - 1); 963 } 964 } 965 966 /* 967 * assert natural sort order is preserved by the codec. 968 */ 969 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 970 byte[][] encoded = new byte[vals.length][]; 971 PositionedByteRange pbr = new SimplePositionedMutableByteRange(); 972 for (int i = 0; i < vals.length; i++) { 973 encoded[i] = new byte[OrderedBytes.blobVarEncodedLength(vals[i].length)]; 974 OrderedBytes.encodeBlobVar(pbr.set(encoded[i]), vals[i], ord); 975 } 976 977 Arrays.sort(encoded, Bytes.BYTES_COMPARATOR); 978 byte[][] sortedVals = Arrays.copyOf(vals, vals.length); 979 980 if (ord == Order.ASCENDING) { 981 Arrays.sort(sortedVals, Bytes.BYTES_COMPARATOR); 982 } else { 983 Arrays.sort(sortedVals, Collections.reverseOrder(Bytes.BYTES_COMPARATOR)); 984 } 985 986 for (int i = 0; i < sortedVals.length; i++) { 987 pbr.set(encoded[i]); 988 byte[] decoded = OrderedBytes.decodeBlobVar(pbr); 989 assertArrayEquals( 990 String.format( 991 "Encoded representations do not preserve natural order: <%s>, <%s>, %s", 992 Arrays.toString(sortedVals[i]), Arrays.toString(decoded), ord), 993 sortedVals[i], decoded); 994 } 995 } 996 } 997 998 /** 999 * Test BlobCopy encoding. 1000 */ 1001 @Test 1002 public void testBlobCopy() { 1003 byte[][] vals = 1004 { Bytes.toBytes(""), 1005 Bytes.toBytes("foo"), 1006 Bytes.toBytes("foobarbazbub"), 1007 { (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, 1008 (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa }, 1009 { (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, 1010 (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55, (byte) 0x55 }, 1011 }; 1012 1013 /* 1014 * assert encoded values match decoded values. encode into target buffer 1015 * starting at an offset to detect over/underflow conditions. 1016 */ 1017 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 1018 for (byte[] val : vals) { 1019 // allocate a buffer 3-bytes larger than necessary to detect over/underflow 1020 int expectedLen = val.length + (Order.ASCENDING == ord ? 1 : 2); 1021 byte[] a = new byte[expectedLen + 3]; 1022 PositionedByteRange buf1 = new SimplePositionedMutableByteRange(a, 1, expectedLen + 1); 1023 buf1.setPosition(1); 1024 1025 // verify encode 1026 assertEquals("Surprising return value.", 1027 expectedLen, OrderedBytes.encodeBlobCopy(buf1, val, ord)); 1028 assertEquals("Broken test: serialization did not consume entire buffer.", 1029 buf1.getLength(), buf1.getPosition()); 1030 assertEquals("Surprising serialized length.", expectedLen, buf1.getPosition() - 1); 1031 assertEquals("Buffer underflow.", 0, a[0]); 1032 assertEquals("Buffer underflow.", 0, a[1]); 1033 assertEquals("Buffer overflow.", 0, a[a.length - 1]); 1034 1035 // verify skip 1036 buf1.setPosition(1); 1037 assertEquals("Surprising return value.", expectedLen, OrderedBytes.skip(buf1)); 1038 assertEquals("Did not skip enough bytes.", expectedLen, buf1.getPosition() - 1); 1039 1040 // verify decode 1041 buf1.setPosition(1); 1042 assertArrayEquals("Deserialization failed.", val, OrderedBytes.decodeBlobCopy(buf1)); 1043 assertEquals("Did not consume enough bytes.", expectedLen, buf1.getPosition() - 1); 1044 } 1045 } 1046 1047 /* 1048 * assert natural sort order is preserved by the codec. 1049 */ 1050 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 1051 byte[][] encoded = new byte[vals.length][]; 1052 PositionedByteRange pbr = new SimplePositionedMutableByteRange(); 1053 for (int i = 0; i < vals.length; i++) { 1054 encoded[i] = new byte[vals[i].length + (Order.ASCENDING == ord ? 1 : 2)]; 1055 OrderedBytes.encodeBlobCopy(pbr.set(encoded[i]), vals[i], ord); 1056 } 1057 1058 Arrays.sort(encoded, Bytes.BYTES_COMPARATOR); 1059 byte[][] sortedVals = Arrays.copyOf(vals, vals.length); 1060 1061 if (ord == Order.ASCENDING) { 1062 Arrays.sort(sortedVals, Bytes.BYTES_COMPARATOR); 1063 } else { 1064 Arrays.sort(sortedVals, Collections.reverseOrder(Bytes.BYTES_COMPARATOR)); 1065 } 1066 1067 for (int i = 0; i < sortedVals.length; i++) { 1068 pbr.set(encoded[i]); 1069 byte[] decoded = OrderedBytes.decodeBlobCopy(pbr); 1070 assertArrayEquals( 1071 String.format( 1072 "Encoded representations do not preserve natural order: <%s>, <%s>, %s", 1073 Arrays.toString(sortedVals[i]), Arrays.toString(decoded), ord), 1074 sortedVals[i], decoded); 1075 } 1076 } 1077 1078 /* 1079 * assert byte[] segments are serialized correctly. 1080 */ 1081 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 1082 byte[] a = new byte[3 + (Order.ASCENDING == ord ? 1 : 2) + 2]; 1083 PositionedByteRange buf = 1084 new SimplePositionedMutableByteRange(a, 1, 3 + (Order.ASCENDING == ord ? 1 : 2)); 1085 OrderedBytes.encodeBlobCopy(buf, Bytes.toBytes("foobarbaz"), 3, 3, ord); 1086 buf.setPosition(0); 1087 assertArrayEquals(Bytes.toBytes("bar"), OrderedBytes.decodeBlobCopy(buf)); 1088 } 1089 } 1090 1091 /** 1092 * Assert invalid input byte[] are rejected by BlobCopy 1093 */ 1094 @Test(expected = IllegalArgumentException.class) 1095 public void testBlobCopyNoZeroBytes() { 1096 byte[] val = { 0x01, 0x02, 0x00, 0x03 }; 1097 // TODO: implementation detail leaked here. 1098 byte[] ascExpected = { 0x38, 0x01, 0x02, 0x00, 0x03 }; 1099 PositionedByteRange buf = new SimplePositionedMutableByteRange(val.length + 1); 1100 OrderedBytes.encodeBlobCopy(buf, val, Order.ASCENDING); 1101 assertArrayEquals(ascExpected, buf.getBytes()); 1102 buf.set(val.length + 2); 1103 OrderedBytes.encodeBlobCopy(buf, val, Order.DESCENDING); 1104 fail("test should never get here."); 1105 } 1106 1107 /** 1108 * Test generic skip logic 1109 */ 1110 @Test 1111 public void testSkip() { 1112 BigDecimal longMax = BigDecimal.valueOf(Long.MAX_VALUE); 1113 double negInf = Double.NEGATIVE_INFINITY; 1114 BigDecimal negLarge = longMax.multiply(longMax).negate(); 1115 BigDecimal negMed = new BigDecimal("-10.0"); 1116 BigDecimal negSmall = new BigDecimal("-0.0010"); 1117 long zero = 0L; 1118 BigDecimal posSmall = negSmall.negate(); 1119 BigDecimal posMed = negMed.negate(); 1120 BigDecimal posLarge = negLarge.negate(); 1121 double posInf = Double.POSITIVE_INFINITY; 1122 double nan = Double.NaN; 1123 byte int8 = 100; 1124 short int16 = 100; 1125 int int32 = 100; 1126 long int64 = 100L; 1127 float float32 = 100.0f; 1128 double float64 = 100.0d; 1129 String text = "hello world."; 1130 byte[] blobVar = Bytes.toBytes("foo"); 1131 byte[] blobCopy = Bytes.toBytes("bar"); 1132 1133 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 1134 PositionedByteRange buff = new SimplePositionedMutableByteRange(30); 1135 int o; 1136 o = OrderedBytes.encodeNull(buff, ord); 1137 buff.setPosition(0); 1138 assertEquals(o, OrderedBytes.skip(buff)); 1139 1140 buff.setPosition(0); 1141 o = OrderedBytes.encodeNumeric(buff, negInf, ord); 1142 buff.setPosition(0); 1143 assertEquals(o, OrderedBytes.skip(buff)); 1144 1145 buff.setPosition(0); 1146 o = OrderedBytes.encodeNumeric(buff, negLarge, ord); 1147 buff.setPosition(0); 1148 assertEquals(o, OrderedBytes.skip(buff)); 1149 1150 buff.setPosition(0); 1151 o = OrderedBytes.encodeNumeric(buff, negMed, ord); 1152 buff.setPosition(0); 1153 assertEquals(o, OrderedBytes.skip(buff)); 1154 1155 buff.setPosition(0); 1156 o = OrderedBytes.encodeNumeric(buff, negSmall, ord); 1157 buff.setPosition(0); 1158 assertEquals(o, OrderedBytes.skip(buff)); 1159 1160 buff.setPosition(0); 1161 o = OrderedBytes.encodeNumeric(buff, zero, ord); 1162 buff.setPosition(0); 1163 assertEquals(o, OrderedBytes.skip(buff)); 1164 1165 buff.setPosition(0); 1166 o = OrderedBytes.encodeNumeric(buff, posSmall, ord); 1167 buff.setPosition(0); 1168 assertEquals(o, OrderedBytes.skip(buff)); 1169 1170 buff.setPosition(0); 1171 o = OrderedBytes.encodeNumeric(buff, posMed, ord); 1172 buff.setPosition(0); 1173 assertEquals(o, OrderedBytes.skip(buff)); 1174 1175 buff.setPosition(0); 1176 o = OrderedBytes.encodeNumeric(buff, posLarge, ord); 1177 buff.setPosition(0); 1178 assertEquals(o, OrderedBytes.skip(buff)); 1179 1180 buff.setPosition(0); 1181 o = OrderedBytes.encodeNumeric(buff, posInf, ord); 1182 buff.setPosition(0); 1183 assertEquals(o, OrderedBytes.skip(buff)); 1184 1185 buff.setPosition(0); 1186 o = OrderedBytes.encodeNumeric(buff, nan, ord); 1187 buff.setPosition(0); 1188 assertEquals(o, OrderedBytes.skip(buff)); 1189 1190 buff.setPosition(0); 1191 o = OrderedBytes.encodeInt8(buff, int8, ord); 1192 buff.setPosition(0); 1193 assertEquals(o, OrderedBytes.skip(buff)); 1194 1195 buff.setPosition(0); 1196 o = OrderedBytes.encodeInt16(buff, int16, ord); 1197 buff.setPosition(0); 1198 assertEquals(o, OrderedBytes.skip(buff)); 1199 1200 buff.setPosition(0); 1201 o = OrderedBytes.encodeInt32(buff, int32, ord); 1202 buff.setPosition(0); 1203 assertEquals(o, OrderedBytes.skip(buff)); 1204 1205 buff.setPosition(0); 1206 o = OrderedBytes.encodeInt64(buff, int64, ord); 1207 buff.setPosition(0); 1208 assertEquals(o, OrderedBytes.skip(buff)); 1209 1210 buff.setPosition(0); 1211 o = OrderedBytes.encodeFloat32(buff, float32, ord); 1212 buff.setPosition(0); 1213 assertEquals(o, OrderedBytes.skip(buff)); 1214 1215 buff.setPosition(0); 1216 o = OrderedBytes.encodeFloat64(buff, float64, ord); 1217 buff.setPosition(0); 1218 assertEquals(o, OrderedBytes.skip(buff)); 1219 1220 buff.setPosition(0); 1221 o = OrderedBytes.encodeString(buff, text, ord); 1222 buff.setPosition(0); 1223 assertEquals(o, OrderedBytes.skip(buff)); 1224 1225 buff.setPosition(0); 1226 o = OrderedBytes.encodeBlobVar(buff, blobVar, ord); 1227 buff.setPosition(0); 1228 assertEquals(o, OrderedBytes.skip(buff)); 1229 1230 // blobCopy is special in that it runs to the end of the target buffer. 1231 buff.set(blobCopy.length + (Order.ASCENDING == ord ? 1 : 2)); 1232 o = OrderedBytes.encodeBlobCopy(buff, blobCopy, ord); 1233 buff.setPosition(0); 1234 assertEquals(o, OrderedBytes.skip(buff)); 1235 } 1236 } 1237 1238 /** 1239 * Test encoded value check 1240 */ 1241 @Test 1242 public void testEncodedValueCheck() { 1243 BigDecimal longMax = BigDecimal.valueOf(Long.MAX_VALUE); 1244 double negInf = Double.NEGATIVE_INFINITY; 1245 BigDecimal negLarge = longMax.multiply(longMax).negate(); 1246 BigDecimal negMed = new BigDecimal("-10.0"); 1247 BigDecimal negSmall = new BigDecimal("-0.0010"); 1248 long zero = 0L; 1249 BigDecimal posSmall = negSmall.negate(); 1250 BigDecimal posMed = negMed.negate(); 1251 BigDecimal posLarge = negLarge.negate(); 1252 double posInf = Double.POSITIVE_INFINITY; 1253 double nan = Double.NaN; 1254 byte int8 = 100; 1255 short int16 = 100; 1256 int int32 = 100; 1257 long int64 = 100L; 1258 float float32 = 100.0f; 1259 double float64 = 100.0d; 1260 String text = "hello world."; 1261 byte[] blobVar = Bytes.toBytes("foo"); 1262 1263 int cnt = 0; 1264 PositionedByteRange buff = new SimplePositionedMutableByteRange(1024); 1265 for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) { 1266 int o; 1267 o = OrderedBytes.encodeNull(buff, ord); cnt++; 1268 o = OrderedBytes.encodeNumeric(buff, negInf, ord); cnt++; 1269 o = OrderedBytes.encodeNumeric(buff, negLarge, ord); cnt++; 1270 o = OrderedBytes.encodeNumeric(buff, negMed, ord); cnt++; 1271 o = OrderedBytes.encodeNumeric(buff, negSmall, ord); cnt++; 1272 o = OrderedBytes.encodeNumeric(buff, zero, ord); cnt++; 1273 o = OrderedBytes.encodeNumeric(buff, posSmall, ord); cnt++; 1274 o = OrderedBytes.encodeNumeric(buff, posMed, ord); cnt++; 1275 o = OrderedBytes.encodeNumeric(buff, posLarge, ord); cnt++; 1276 o = OrderedBytes.encodeNumeric(buff, posInf, ord); cnt++; 1277 o = OrderedBytes.encodeNumeric(buff, nan, ord); cnt++; 1278 o = OrderedBytes.encodeInt8(buff, int8, ord); cnt++; 1279 o = OrderedBytes.encodeInt16(buff, int16, ord); cnt++; 1280 o = OrderedBytes.encodeInt32(buff, int32, ord); cnt++; 1281 o = OrderedBytes.encodeInt64(buff, int64, ord); cnt++; 1282 o = OrderedBytes.encodeFloat32(buff, float32, ord); cnt++; 1283 o = OrderedBytes.encodeFloat64(buff, float64, ord); cnt++; 1284 o = OrderedBytes.encodeString(buff, text, ord); cnt++; 1285 o = OrderedBytes.encodeBlobVar(buff, blobVar, ord); cnt++; 1286 } 1287 1288 buff.setPosition(0); 1289 assertEquals(OrderedBytes.length(buff), cnt); 1290 for (int i = 0; i < cnt; i++) { 1291 assertTrue(OrderedBytes.isEncodedValue(buff)); 1292 OrderedBytes.skip(buff); 1293 } 1294 } 1295}