Skip to content

Commit

Permalink
Make UnsignedBytesTest actually check that we are using the correct…
Browse files Browse the repository at this point in the history
… endianness for reads.

I noticed this during work to [avoid using `Unsafe`](#6806) (though it applies even if we do use `Unsafe`, as you'd guess from the `BIG_ENDIAN` check there).

RELNOTES=n/a
PiperOrigin-RevId: 715368993
  • Loading branch information
cpovirk authored and Google Java Core Libraries committed Jan 14, 2025
1 parent ee63055 commit 71d0692
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static com.google.common.primitives.UnsignedBytes.min;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static java.lang.Math.signum;
import static org.junit.Assert.assertThrows;

import com.google.common.collect.testing.Helpers;
Expand Down Expand Up @@ -95,8 +96,8 @@ public void testCompare() {
byte y = VALUES[j];
// note: spec requires only that the sign is the same
assertWithMessage(x + ", " + y)
.that(Math.signum(UnsignedBytes.compare(x, y)))
.isEqualTo(Math.signum(Integer.compare(i, j)));
.that(signum(UnsignedBytes.compare(x, y)))
.isEqualTo(signum(Integer.compare(i, j)));
}
}
}
Expand Down Expand Up @@ -264,7 +265,7 @@ public void testLexicographicalComparator() {
new byte[] {GREATEST, GREATEST},
new byte[] {GREATEST, GREATEST, GREATEST});

// The Unsafe implementation if it's available. Otherwise, the Java implementation.
// The VarHandle, Unsafe, or Java implementation.
Comparator<byte[]> comparator = UnsignedBytes.lexicographicalComparator();
Helpers.testComparator(comparator, ordered);
assertThat(SerializableTester.reserialize(comparator)).isSameInstanceAs(comparator);
Expand All @@ -275,26 +276,42 @@ public void testLexicographicalComparator() {
assertThat(SerializableTester.reserialize(javaImpl)).isSameInstanceAs(javaImpl);
}

public void testLexicographicalComparatorLongInputs() {
Random rnd = new Random();
for (Comparator<byte[]> comparator :
Arrays.asList(
UnsignedBytes.lexicographicalComparator(),
UnsignedBytes.lexicographicalComparatorJavaImpl())) {
for (int trials = 10; trials-- > 0; ) {
byte[] left = new byte[1 + rnd.nextInt(32)];
rnd.nextBytes(left);
byte[] right = left.clone();
assertThat(comparator.compare(left, right)).isEqualTo(0);
int i = rnd.nextInt(left.length);
left[i] ^= (byte) (1 + rnd.nextInt(255));
assertThat(comparator.compare(left, right)).isNotEqualTo(0);
assertThat(UnsignedBytes.compare(left[i], right[i]) > 0)
.isEqualTo(comparator.compare(left, right) > 0);
}
public void testLexicographicalComparatorLongPseudorandomInputs() {
Comparator<byte[]> comparator1 = UnsignedBytes.lexicographicalComparator();
Comparator<byte[]> comparator2 = UnsignedBytes.lexicographicalComparatorJavaImpl();
Random rnd = new Random(714958103);
for (int trial = 0; trial < 100; trial++) {
byte[] left = new byte[1 + rnd.nextInt(32)];
rnd.nextBytes(left);
byte[] right = left.clone();
assertThat(comparator1.compare(left, right)).isEqualTo(0);
assertThat(comparator2.compare(left, right)).isEqualTo(0);
int i = rnd.nextInt(left.length);
left[i] ^= (byte) (1 + rnd.nextInt(255));
assertThat(signum(comparator1.compare(left, right)))
.isEqualTo(signum(UnsignedBytes.compare(left[i], right[i])));
assertThat(signum(comparator2.compare(left, right)))
.isEqualTo(signum(UnsignedBytes.compare(left[i], right[i])));
}
}

public void testLexicographicalComparatorLongHandwrittenInputs() {
Comparator<byte[]> comparator1 = UnsignedBytes.lexicographicalComparator();
Comparator<byte[]> comparator2 = UnsignedBytes.lexicographicalComparatorJavaImpl();

/*
* These arrays are set up to test that the comparator compares bytes within a word in the
* correct order—in order words, that it doesn't mix up big-endian and little-endian. The first
* array has a smaller element at one index, and then the second array has a smaller elements at
* the next.
*/
byte[] a0 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 99, 15, 16, 17};
byte[] b0 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 99, 14, 15, 16, 17};

assertThat(comparator1.compare(a0, b0)).isLessThan(0);
assertThat(comparator2.compare(a0, b0)).isLessThan(0);
}

public void testSort() {
testSort(new byte[] {}, new byte[] {});
testSort(new byte[] {2}, new byte[] {2});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static com.google.common.primitives.UnsignedBytes.min;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static java.lang.Math.signum;
import static org.junit.Assert.assertThrows;

import com.google.common.collect.testing.Helpers;
Expand Down Expand Up @@ -96,8 +97,8 @@ public void testCompare() {
byte y = VALUES[j];
// note: spec requires only that the sign is the same
assertWithMessage(x + ", " + y)
.that(Math.signum(UnsignedBytes.compare(x, y)))
.isEqualTo(Math.signum(Integer.compare(i, j)));
.that(signum(UnsignedBytes.compare(x, y)))
.isEqualTo(signum(Integer.compare(i, j)));
}
}
}
Expand Down Expand Up @@ -267,7 +268,7 @@ public void testLexicographicalComparator() {
new byte[] {GREATEST, GREATEST},
new byte[] {GREATEST, GREATEST, GREATEST});

// The Unsafe implementation if it's available. Otherwise, the Java implementation.
// The VarHandle, Unsafe, or Java implementation.
Comparator<byte[]> comparator = UnsignedBytes.lexicographicalComparator();
Helpers.testComparator(comparator, ordered);
assertThat(SerializableTester.reserialize(comparator)).isSameInstanceAs(comparator);
Expand All @@ -278,26 +279,42 @@ public void testLexicographicalComparator() {
assertThat(SerializableTester.reserialize(javaImpl)).isSameInstanceAs(javaImpl);
}

public void testLexicographicalComparatorLongInputs() {
Random rnd = new Random();
for (Comparator<byte[]> comparator :
Arrays.asList(
UnsignedBytes.lexicographicalComparator(),
UnsignedBytes.lexicographicalComparatorJavaImpl())) {
for (int trials = 10; trials-- > 0; ) {
byte[] left = new byte[1 + rnd.nextInt(32)];
rnd.nextBytes(left);
byte[] right = left.clone();
assertThat(comparator.compare(left, right)).isEqualTo(0);
int i = rnd.nextInt(left.length);
left[i] ^= (byte) (1 + rnd.nextInt(255));
assertThat(comparator.compare(left, right)).isNotEqualTo(0);
assertThat(UnsignedBytes.compare(left[i], right[i]) > 0)
.isEqualTo(comparator.compare(left, right) > 0);
}
public void testLexicographicalComparatorLongPseudorandomInputs() {
Comparator<byte[]> comparator1 = UnsignedBytes.lexicographicalComparator();
Comparator<byte[]> comparator2 = UnsignedBytes.lexicographicalComparatorJavaImpl();
Random rnd = new Random(714958103);
for (int trial = 0; trial < 100; trial++) {
byte[] left = new byte[1 + rnd.nextInt(32)];
rnd.nextBytes(left);
byte[] right = left.clone();
assertThat(comparator1.compare(left, right)).isEqualTo(0);
assertThat(comparator2.compare(left, right)).isEqualTo(0);
int i = rnd.nextInt(left.length);
left[i] ^= (byte) (1 + rnd.nextInt(255));
assertThat(signum(comparator1.compare(left, right)))
.isEqualTo(signum(UnsignedBytes.compare(left[i], right[i])));
assertThat(signum(comparator2.compare(left, right)))
.isEqualTo(signum(UnsignedBytes.compare(left[i], right[i])));
}
}

public void testLexicographicalComparatorLongHandwrittenInputs() {
Comparator<byte[]> comparator1 = UnsignedBytes.lexicographicalComparator();
Comparator<byte[]> comparator2 = UnsignedBytes.lexicographicalComparatorJavaImpl();

/*
* These arrays are set up to test that the comparator compares bytes within a word in the
* correct order—in order words, that it doesn't mix up big-endian and little-endian. The first
* array has a smaller element at one index, and then the second array has a smaller elements at
* the next.
*/
byte[] a0 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 99, 15, 16, 17};
byte[] b0 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 99, 14, 15, 16, 17};

assertThat(comparator1.compare(a0, b0)).isLessThan(0);
assertThat(comparator2.compare(a0, b0)).isLessThan(0);
}

public void testSort() {
testSort(new byte[] {}, new byte[] {});
testSort(new byte[] {2}, new byte[] {2});
Expand Down

0 comments on commit 71d0692

Please sign in to comment.