/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.beam.sdk.io.range;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Tests of {@link ByteKey}.
*/
@RunWith(JUnit4.class)
public class ByteKeyTest {
/* A big list of byte[] keys, in ascending sorted order. */
static final ByteKey[] TEST_KEYS =
new ByteKey[] {
ByteKey.EMPTY,
ByteKey.of(0),
ByteKey.of(0, 1),
ByteKey.of(0, 1, 1),
ByteKey.of(0, 1, 2),
ByteKey.of(0, 1, 2, 0xfe),
ByteKey.of(0, 1, 3, 0xfe),
ByteKey.of(0, 0xfe, 0xfe, 0xfe),
ByteKey.of(0, 0xfe, 0xfe, 0xff),
ByteKey.of(0, 0xfe, 0xff, 0),
ByteKey.of(0, 0xff, 0xff, 0),
ByteKey.of(0, 0xff, 0xff, 1),
ByteKey.of(0, 0xff, 0xff, 0xfe),
ByteKey.of(0, 0xff, 0xff, 0xff),
ByteKey.of(1),
ByteKey.of(1, 2),
ByteKey.of(1, 2, 3),
ByteKey.of(3),
ByteKey.of(0xdd),
ByteKey.of(0xfe),
ByteKey.of(0xfe, 0xfe),
ByteKey.of(0xfe, 0xff),
ByteKey.of(0xff),
ByteKey.of(0xff, 0),
ByteKey.of(0xff, 0xfe),
ByteKey.of(0xff, 0xff),
ByteKey.of(0xff, 0xff, 0xff),
ByteKey.of(0xff, 0xff, 0xff, 0xff),
};
/**
* Tests {@link ByteKey#compareTo(ByteKey)} using exhaustive testing within a large sorted list
* of keys.
*/
@Test
public void testCompareToExhaustive() {
// Verify that the comparison gives the correct result for all values in both directions.
for (int i = 0; i < TEST_KEYS.length; ++i) {
for (int j = 0; j < TEST_KEYS.length; ++j) {
ByteKey left = TEST_KEYS[i];
ByteKey right = TEST_KEYS[j];
int cmp = left.compareTo(right);
if (i < j && !(cmp < 0)) {
fail(
String.format(
"Expected that cmp(%s, %s) < 0, got %d [i=%d, j=%d]", left, right, cmp, i, j));
} else if (i == j && !(cmp == 0)) {
fail(
String.format(
"Expected that cmp(%s, %s) == 0, got %d [i=%d, j=%d]", left, right, cmp, i, j));
} else if (i > j && !(cmp > 0)) {
fail(
String.format(
"Expected that cmp(%s, %s) > 0, got %d [i=%d, j=%d]", left, right, cmp, i, j));
}
}
}
}
/**
* Tests {@link ByteKey#equals}.
*/
@Test
public void testEquals() {
// Verify that the comparison gives the correct result for all values in both directions.
for (int i = 0; i < TEST_KEYS.length; ++i) {
for (int j = 0; j < TEST_KEYS.length; ++j) {
ByteKey left = TEST_KEYS[i];
ByteKey right = TEST_KEYS[j];
boolean eq = left.equals(right);
if (i == j) {
assertTrue(String.format("Expected that %s is equal to itself.", left), eq);
assertTrue(
String.format("Expected that %s is equal to a copy of itself.", left),
left.equals(ByteKey.copyFrom(right.getValue())));
} else {
assertFalse(String.format("Expected that %s is not equal to %s", left, right), eq);
}
}
}
}
/**
* Tests {@link ByteKey#hashCode}.
*/
@Test
public void testHashCode() {
// Verify that the hashCode is equal when i==j, and usually not equal otherwise.
int collisions = 0;
for (int i = 0; i < TEST_KEYS.length; ++i) {
int left = TEST_KEYS[i].hashCode();
int leftClone = ByteKey.copyFrom(TEST_KEYS[i].getValue()).hashCode();
assertEquals(
String.format("Expected same hash code for %s and a copy of itself", TEST_KEYS[i]),
left,
leftClone);
for (int j = i + 1; j < TEST_KEYS.length; ++j) {
int right = TEST_KEYS[j].hashCode();
if (left == right) {
++collisions;
}
}
}
int totalUnequalTests = TEST_KEYS.length * (TEST_KEYS.length - 1) / 2;
assertThat("Too many hash collisions", collisions, lessThan(totalUnequalTests / 2));
}
/**
* Tests {@link ByteKey#toString}.
*/
@Test
public void testToString() {
assertEquals("[]", ByteKey.EMPTY.toString());
assertEquals("[00]", ByteKey.of(0).toString());
assertEquals("[0000]", ByteKey.of(0x00, 0x00).toString());
assertEquals(
"[0123456789abcdef]",
ByteKey.of(0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef).toString());
}
/**
* Tests {@link ByteKey#isEmpty}.
*/
@Test
public void testIsEmpty() {
assertTrue("[] is empty", ByteKey.EMPTY.isEmpty());
assertFalse("[00]", ByteKey.of(0).isEmpty());
}
/**
* Tests {@link ByteKey#getBytes}.
*/
@Test
public void testGetBytes() {
assertTrue("[] equal after getBytes", Arrays.equals(new byte[] {}, ByteKey.EMPTY.getBytes()));
assertTrue(
"[00] equal after getBytes", Arrays.equals(new byte[] {0x00}, ByteKey.of(0x00).getBytes()));
}
}