Skip to content

Instantly share code, notes, and snippets.

@DanielThomas
Last active March 25, 2024 22:26
Show Gist options
  • Save DanielThomas/f74d8937a5440685ceef07a70df6433c to your computer and use it in GitHub Desktop.
Save DanielThomas/f74d8937a5440685ceef07a70df6433c to your computer and use it in GitHub Desktop.
Tests for HashIndex.java
/*
* Copyright 2024 Netflix Inc.
*
* Licensed 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 com.netflix.index;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.io.*;
import java.util.*;
import java.util.stream.LongStream;
import java.util.zip.DeflaterInputStream;
import java.util.zip.GZIPInputStream;
import static org.junit.jupiter.api.Assertions.*;
class HashIndexTest {
@Test
public void getValueMissing() {
HashIndex<String> index = new HashIndex<>(10, Long.BYTES);
HashIndex.OptionalNumber actual = index.getValue(0, value -> {
throw new IllegalStateException(); // predicate should not be called
});
assertFalse(actual.isPresent());
}
@Test
public void getValueMaxKey() {
HashIndex<String> index = new HashIndex<>(10, Long.BYTES);
HashIndex.OptionalNumber actual = index.getValue(Long.MAX_VALUE, value -> {
throw new IllegalStateException(); // predicate should not be called
});
assertFalse(actual.isPresent());
}
@Test
public void getValuePresent() {
HashIndex<String> index = new HashIndex<>(10, Long.BYTES);
index.put(0, 0);
HashIndex.OptionalNumber actual = index.getValue(0, value -> true);
assertTrue(actual.isPresent());
assertEquals(0, actual.getAsByte());
}
@Test
public void getValueNotEqual() {
HashIndex<String> index = new HashIndex<>(10, Long.BYTES);
index.put(0, 0);
HashIndex.OptionalNumber actual = index.getValue(0, value -> false);
assertFalse(actual.isPresent());
}
@Test
public void getValueDuplicateKeys() {
HashIndex<String> index = new HashIndex<>(10, Long.BYTES);
index.put(1, 1);
index.put(1, 2);
index.put(1, 3);
index.put(1, 4);
index.put(1, 5);
List<Long> values = new ArrayList<>();
HashIndex.OptionalNumber actual = index.getValue(1, value -> {
values.add(value);
return value == 5;
});
assertTrue(actual.isPresent());
assertEquals(5, actual.get());
assertEquals(5, values.size());
}
@Test
public void getValueNarrowingDisallowed() {
HashIndex<String> index = new HashIndex<>(1, Long.BYTES);
index.put(0, Long.MAX_VALUE - 1);
Arrays.asList(Byte.BYTES, Short.BYTES, Integer.BYTES).forEach(numBytes -> {
Exception exception = assertThrows(IllegalArgumentException.class, () -> {
HashIndex.OptionalNumber result = index.getValue(0, value -> true);
switch (numBytes) {
case Byte.BYTES:
result.getAsByte();
break;
case Short.BYTES:
result.getAsShort();
break;
case Integer.BYTES:
result.getAsInt();
break;
default:
result.get();
}
});
assertEquals("value is larger than " + numBytes * Byte.SIZE + " bits", exception.getMessage());
});
}
@Test
public void getMissing() {
HashIndex<String> index = new HashIndex<>(10, Long.BYTES);
Optional<String> actual = index.get(0, value -> {
throw new IllegalStateException();
});
assertFalse(actual.isPresent());
}
@Test
public void getPresent() {
HashIndex<String> index = new HashIndex<>(10, Long.BYTES);
index.put(0, 0);
Optional<String> actual = index.get(0, value -> Optional.of("match"));
assertTrue(actual.isPresent());
assertEquals("match", actual.get());
}
@Test
public void getNotEqual() {
HashIndex<String> index = new HashIndex<>(10, Long.BYTES);
index.put(0, 0);
Optional<String> actual = index.get(0, value -> Optional.empty());
assertFalse(actual.isPresent());
}
@ParameterizedTest
@ValueSource(longs = {(long) Byte.MAX_VALUE, (long) Short.MAX_VALUE, (long) Integer.MAX_VALUE, Long.MAX_VALUE})
public void putMaxValueDisallowed(long expected) {
int entryBytes = (Long.SIZE - Long.numberOfLeadingZeros(expected) + 1) / Byte.SIZE;
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
HashIndex<String> index = new HashIndex<>(1, entryBytes);
index.put(0, expected);
});
assertEquals(expected + " is reserved for " + entryBytes + " byte entries", exception.getMessage());
}
@ParameterizedTest
@ValueSource(longs = {(long) Byte.MAX_VALUE, (long) Short.MAX_VALUE, (long) Integer.MAX_VALUE, Long.MAX_VALUE})
public void putMaxValueMinusOne(long expected) {
int entryBytes = (Long.SIZE - Long.numberOfLeadingZeros(expected) + 1) / Byte.SIZE;
expected = expected - 1;
HashIndex<String> index = new HashIndex<>(1, entryBytes);
index.put(0, expected);
long actual = index.getValue(0, value -> true).get();
assertEquals(expected, actual);
}
@ParameterizedTest
@ValueSource(longs = {(long) Byte.MIN_VALUE, (long) Short.MIN_VALUE, (long) Integer.MIN_VALUE, Long.MIN_VALUE})
public void putMinValue(long expected) {
int numEntries = (Long.SIZE - Long.numberOfLeadingZeros(~expected) + 1) / Byte.SIZE;
HashIndex<String> index = new HashIndex<>(1, numEntries);
index.put(0, expected);
long actual = index.getValue(0, value -> true).get();
assertEquals(expected, actual);
}
@ParameterizedTest
@ValueSource(ints = {Byte.BYTES, Short.BYTES, Integer.BYTES})
public void putNarrowingDisallowed(int numBytes) {
Exception exception = assertThrows(IllegalArgumentException.class, () -> {
HashIndex<String> index = new HashIndex<>(1, numBytes);
index.put(0, 1L << numBytes * Byte.SIZE);
});
assertEquals("value is larger than " + numBytes * Byte.SIZE + " bits", exception.getMessage());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment