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