package tests;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.checkerframework.common.value.util.Range;
import org.junit.Test;
/** This class tests the Range class, independent of the Value Checker. */
public class RangeTest {
// These sets of values may be excessively long; perhaps trim them down later.
long[] rangeBounds = {
Long.MIN_VALUE,
Long.MIN_VALUE + 1,
Integer.MIN_VALUE - 1000L,
Integer.MIN_VALUE - 10L,
Integer.MIN_VALUE,
Integer.MIN_VALUE + 1L,
Short.MIN_VALUE - 1000L,
Short.MIN_VALUE - 10L,
Short.MIN_VALUE,
Short.MIN_VALUE + 1L,
Byte.MIN_VALUE - 1000L,
Byte.MIN_VALUE - 10L,
Byte.MIN_VALUE,
Byte.MIN_VALUE + 1L,
0L,
Byte.MAX_VALUE - 1L,
Byte.MAX_VALUE,
Byte.MAX_VALUE + 10L,
Byte.MAX_VALUE + 1000L,
Short.MAX_VALUE - 1L,
Short.MAX_VALUE,
Short.MAX_VALUE + 10L,
Short.MAX_VALUE + 1000L,
Integer.MAX_VALUE - 1,
Integer.MAX_VALUE,
Integer.MAX_VALUE + 10L,
Integer.MAX_VALUE + 1000L,
Long.MAX_VALUE - 1,
Long.MAX_VALUE
};
long[] values = {
Long.MIN_VALUE,
Long.MIN_VALUE + 1L,
Integer.MIN_VALUE,
Integer.MIN_VALUE + 1L,
Short.MIN_VALUE,
Short.MIN_VALUE + 1L,
Byte.MIN_VALUE,
Byte.MIN_VALUE + 1L,
-8L,
-4L,
-2L,
-1L,
0L,
1L,
2L,
4L,
8L,
Byte.MAX_VALUE - 1L,
Byte.MAX_VALUE,
Short.MAX_VALUE - 1L,
Short.MAX_VALUE,
Integer.MAX_VALUE - 1L,
Integer.MAX_VALUE,
Long.MAX_VALUE - 1L,
Long.MAX_VALUE
};
Range[] ranges;
static final long intWidth = (long) Integer.MAX_VALUE - (long) Integer.MIN_VALUE + 1;
static final long shortWidth = Short.MAX_VALUE - Short.MIN_VALUE + 1;
static final long byteWidth = Byte.MAX_VALUE - Byte.MIN_VALUE + 1;
public RangeTest() {
// Initialize the ranges list.
List<Range> rangesList = new ArrayList<Range>();
for (long lowerbound : rangeBounds) {
for (long upperbound : rangeBounds) {
if (lowerbound <= upperbound) {
rangesList.add(new Range(lowerbound, upperbound));
}
}
}
ranges = rangesList.toArray(new Range[0]);
}
/** The element is a member of the range. */
class RangeAndElement {
Range range;
long element;
RangeAndElement(Range range, long element) {
if (!range.contains(element)) {
throw new IllegalArgumentException();
}
this.range = range;
this.element = element;
}
}
class RangeAndTwoElements {
Range range;
long a;
long b;
}
ValuesInRangeIterator valuesInRange(Range r) {
return new ValuesInRangeIterator(r);
}
RangeAndElementIterator rangeAndElements() {
return new RangeAndElementIterator();
}
class RangeAndElementIterator implements Iterator<RangeAndElement>, Iterable<RangeAndElement> {
// This is the index of the range that is currently being examined.
// It is in [0..ranges.length].
int ri;
Range range;
ValuesInRangeIterator vi;
RangeAndElement nextValue;
boolean nextValueValid = false;
public RangeAndElementIterator() {
ri = 0;
range = ranges[ri];
vi = new ValuesInRangeIterator(range);
}
@Override
public RangeAndElement next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
nextValueValid = false;
return nextValue;
}
@Override
public boolean hasNext() {
if (nextValueValid) {
return true;
}
while (!vi.hasNext()) {
ri++;
if (ri == ranges.length) {
return false;
}
range = ranges[ri];
vi = new ValuesInRangeIterator(range);
}
nextValue = new RangeAndElement(range, vi.next());
nextValueValid = true;
return true;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public Iterator<RangeAndElement> iterator() {
return this;
}
}
class ValuesInRangeIterator implements Iterator<Long>, Iterable<Long> {
Range range;
// This is the first index that has NOT been examined. It is in [0..values.length].
int i = 0;
long nextValue;
boolean nextValueValid = false;
public ValuesInRangeIterator(Range range) {
this.range = range;
}
@Override
public Long next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
nextValueValid = false;
return nextValue;
}
@Override
public boolean hasNext() {
if (nextValueValid) {
return true;
}
while (i < values.length) {
nextValue = values[i];
i++;
if (range.contains(nextValue)) {
nextValueValid = true;
break;
}
}
return nextValueValid;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public Iterator<Long> iterator() {
return this;
}
}
@Test
public void testIntRange() {
for (Range range : ranges) {
Range result = range.intRange();
for (long value : values) {
if (value < range.from + intWidth
&& value > range.to - intWidth
&& (Math.abs(range.from) - 1) / Integer.MIN_VALUE
== (Math.abs(range.to) - 1) / Integer.MIN_VALUE) {
// filter out test data that would cause Range.intRange to return INT_EVERYTHING
int intValue = (int) value;
assert range.contains(value) && result.contains(intValue)
|| !range.contains(value) && !result.contains(intValue)
: String.format(
"Range.intRange failure: %s => %s; witness = %s",
range, result, intValue);
}
}
}
}
@Test
public void testShortRange() {
for (Range range : ranges) {
Range result = range.shortRange();
for (long value : values) {
if (value < range.from + shortWidth
&& value > range.to - shortWidth
&& (Math.abs(range.from) - 1) / Short.MIN_VALUE
== (Math.abs(range.to) - 1) / Short.MIN_VALUE) {
// filter out test data that would cause Range.shortRange to return SHORT_EVERYTHING
short shortValue = (short) value;
assert range.contains(value) && result.contains(shortValue)
|| !range.contains(value) && !result.contains(shortValue)
: String.format(
"Range.shortRange failure: %s => %s; witness = %s",
range, result, shortValue);
}
}
}
}
@Test
public void testByteRange() {
for (Range range : ranges) {
Range result = range.byteRange();
for (long value : values) {
if (value < range.from + byteWidth
&& value > range.to - byteWidth
&& (Math.abs(range.from) - 1) / Byte.MIN_VALUE
== (Math.abs(range.to) - 1) / Byte.MIN_VALUE) {
// filter out test data that would cause Range.ByteRange to return BYTE_EVERYTHING
byte byteValue = (byte) value;
assert range.contains(value) && result.contains(byteValue)
|| !range.contains(value) && !result.contains(byteValue)
: String.format(
"Range.byteRange failure: %s => %s; witness = %s",
range, result, byteValue);
}
}
}
}
@Test
public void testUnion() {
for (Range range1 : ranges) {
for (Range range2 : ranges) {
Range result = range1.union(range2);
for (long value : values) {
if (range1.contains(value) || range2.contains(value)) {
assert result.contains(value)
: String.format(
"Range.union failure: %s %s %s; witness = %s",
range1, range2, result, value);
}
}
}
}
}
@Test
public void testIntersect() {
for (Range range1 : ranges) {
for (Range range2 : ranges) {
Range result = range1.intersect(range2);
for (long value : values) {
assert ((range1.contains(value) && range2.contains(value))
== (result.contains(value)))
: String.format(
"Range.intersect failure: %s %s => %s; witness = %s",
range1, range2, result, value);
}
}
}
}
@Test
public void testPlus() {
for (RangeAndElement re1 : rangeAndElements()) {
for (RangeAndElement re2 : rangeAndElements()) {
Range result = re1.range.plus(re2.range);
assert result.contains(re1.element + re2.element)
: String.format(
"Range.plus failure: %s %s => %s; witnesses %s + %s => %s",
re1.range,
re2.range,
result,
re1.element,
re2.element,
re1.element + re2.element);
}
}
}
@Test
public void testMinus() {
for (RangeAndElement re1 : rangeAndElements()) {
for (RangeAndElement re2 : rangeAndElements()) {
Range result = re1.range.minus(re2.range);
assert result.contains(re1.element - re2.element)
: String.format(
"Range.minus failure: %s %s => %s; witnesses %s - %s => %s",
re1.range,
re2.range,
result,
re1.element,
re2.element,
re1.element - re2.element);
}
}
}
@Test
public void testTimes() {
for (RangeAndElement re1 : rangeAndElements()) {
for (RangeAndElement re2 : rangeAndElements()) {
Range result = re1.range.times(re2.range);
assert result.contains(re1.element * re2.element)
: String.format(
"Range.times failure: %s %s => %s; witnesses %s * %s => %s",
re1.range,
re2.range,
result,
re1.element,
re2.element,
re1.element * re2.element);
}
}
}
@Test
public void testDivide() {
assert new Range(1, 2).divide(new Range(0, 0)) == Range.NOTHING;
for (RangeAndElement re1 : rangeAndElements()) {
for (RangeAndElement re2 : rangeAndElements()) {
if (re2.element == 0) {
continue;
}
Range result = re1.range.divide(re2.range);
Long witness = re1.element / re2.element;
assert result.contains(witness)
: String.format(
"Range.divide failure: %s %s => %s; witnesses %s / %s => %s",
re1.range, re2.range, result, re1.element, re2.element, witness);
}
}
}
@Test
public void testRemainder() {
assert new Range(1, 2).remainder(new Range(0, 0)) == Range.NOTHING;
for (RangeAndElement re1 : rangeAndElements()) {
for (RangeAndElement re2 : rangeAndElements()) {
if (re2.element == 0) {
continue;
}
Range result = re1.range.remainder(re2.range);
Long witness = re1.element % re2.element;
assert result.contains(witness)
: String.format(
"Range.divide failure: %s %s => %s; witnesses %s %% %s => %s",
re1.range, re2.range, result, re1.element, re2.element, witness);
}
}
}
@Test
public void testShiftLeft() {
for (RangeAndElement re1 : rangeAndElements()) {
for (RangeAndElement re2 : rangeAndElements()) {
Range result = re1.range.shiftLeft(re2.range);
assert result.contains(re1.element << re2.element)
: String.format(
"Range.shiftLeft failure: %s %s => %s; witnesses %s << %s => %s",
re1.range,
re2.range,
result,
re1.element,
re2.element,
re1.element << re2.element);
}
}
}
@Test
public void testSignedShiftRight() {
for (RangeAndElement re1 : rangeAndElements()) {
for (RangeAndElement re2 : rangeAndElements()) {
Range result = re1.range.signedShiftRight(re2.range);
assert result.contains(re1.element >> re2.element)
: String.format(
"Range.signedShiftRight failure: %s %s => %s; witnesses %s >> %s => %s",
re1.range,
re2.range,
result,
re1.element,
re2.element,
re1.element >> re2.element);
}
}
}
@Test
public void testUnaryPlus() {
for (RangeAndElement re : rangeAndElements()) {
Range result = re.range.unaryPlus();
assert result.contains(+re.element)
: String.format(
"Range.unaryPlus failure: %s => %s; witness %s => %s",
re.range, result, re.element, +re.element);
}
}
@Test
public void testUnaryMinus() {
for (RangeAndElement re : rangeAndElements()) {
Range result = re.range.unaryMinus();
assert result.contains(-re.element)
: String.format(
"Range.unaryMinus failure: %s => %s; witness %s => %s",
re.range, result, re.element, -re.element);
}
}
@Test
public void testBitwiseComplement() {
for (RangeAndElement re : rangeAndElements()) {
Range result = re.range.bitwiseComplement();
assert result.contains(~re.element)
: String.format(
"Range.bitwiseComplement failure: %s => %s; witness %s => %s",
re.range, result, re.element, ~re.element);
}
}
@Test
public void testLessThan() {
for (Range range1 : ranges) {
for (Range range2 : ranges) {
for (long value : values) {
Range result = range1.refineLessThan(range2);
assert (value >= range2.to
? !result.contains(value)
: range1.contains(value) == result.contains(value))
: String.format(
"Range.refineLessThan failure: %s %s %s; witness = %s",
range1, range2, result, value);
}
}
}
}
@Test
public void testLessThanEq() {
for (Range range1 : ranges) {
for (Range range2 : ranges) {
for (long value : values) {
Range result = range1.refineLessThanEq(range2);
assert (value > range2.to
? !result.contains(value)
: range1.contains(value) == result.contains(value))
: String.format(
"Range.refineLessThanEq failure: %s %s %s; witness = %s",
range1, range2, result, value);
}
}
}
}
@Test
public void testGreaterThan() {
for (Range range1 : ranges) {
for (Range range2 : ranges) {
for (long value : values) {
Range result = range1.refineGreaterThan(range2);
assert (value <= range2.from
? !result.contains(value)
: range1.contains(value) == result.contains(value))
: String.format(
"Range.refineGreaterThan failure: %s %s %s; witness = %s",
range1, range2, result, value);
}
}
}
}
@Test
public void testGreaterThanEq() {
for (Range range1 : ranges) {
for (Range range2 : ranges) {
for (long value : values) {
Range result = range1.refineGreaterThanEq(range2);
assert (value < range2.from
? !result.contains(value)
: range1.contains(value) == result.contains(value))
: String.format(
"Range.refineGreaterThanEq failure: %s %s %s; witness = %s",
range1, range2, result, value);
}
}
}
}
@Test
public void testEqualTo() {
for (Range range1 : ranges) {
for (Range range2 : ranges) {
for (long value : values) {
Range result = range1.refineEqualTo(range2);
assert (value < range2.from || value > range2.to
? !result.contains(value)
: range1.contains(value) == result.contains(value))
: String.format(
"Range.refineEqualTo failure: %s %s %s; witness = %s",
range1, range2, result, value);
}
}
}
}
}