1 /* 2 * Copyright (C) 2008 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.primitives; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 import static org.junit.Assert.assertThrows; 22 23 import com.google.common.collect.testing.Helpers; 24 import com.google.common.testing.NullPointerTester; 25 import com.google.common.testing.SerializableTester; 26 import java.util.Arrays; 27 import java.util.Comparator; 28 import java.util.List; 29 import java.util.Random; 30 import junit.framework.TestCase; 31 32 /** 33 * Unit test for {@link UnsignedBytes}. 34 * 35 * @author Kevin Bourrillion 36 * @author Louis Wasserman 37 */ 38 public class UnsignedBytesTest extends TestCase { 39 private static final byte LEAST = 0; 40 private static final byte GREATEST = (byte) 255; 41 42 // Only in this class, VALUES must be strictly ascending 43 private static final byte[] VALUES = {LEAST, 127, (byte) 128, (byte) 129, GREATEST}; 44 testToInt()45 public void testToInt() { 46 assertThat(UnsignedBytes.toInt((byte) 0)).isEqualTo(0); 47 assertThat(UnsignedBytes.toInt((byte) 1)).isEqualTo(1); 48 assertThat(UnsignedBytes.toInt((byte) 127)).isEqualTo(127); 49 assertThat(UnsignedBytes.toInt((byte) -128)).isEqualTo(128); 50 assertThat(UnsignedBytes.toInt((byte) -127)).isEqualTo(129); 51 assertThat(UnsignedBytes.toInt((byte) -1)).isEqualTo(255); 52 } 53 testCheckedCast()54 public void testCheckedCast() { 55 for (byte value : VALUES) { 56 assertThat(UnsignedBytes.checkedCast(UnsignedBytes.toInt(value))).isEqualTo(value); 57 } 58 assertCastFails(256L); 59 assertCastFails(-1L); 60 assertCastFails(Long.MAX_VALUE); 61 assertCastFails(Long.MIN_VALUE); 62 } 63 testSaturatedCast()64 public void testSaturatedCast() { 65 for (byte value : VALUES) { 66 assertThat(UnsignedBytes.saturatedCast(UnsignedBytes.toInt(value))).isEqualTo(value); 67 } 68 assertThat(UnsignedBytes.saturatedCast(256L)).isEqualTo(GREATEST); 69 assertThat(UnsignedBytes.saturatedCast(-1L)).isEqualTo(LEAST); 70 assertThat(UnsignedBytes.saturatedCast(Long.MAX_VALUE)).isEqualTo(GREATEST); 71 assertThat(UnsignedBytes.saturatedCast(Long.MIN_VALUE)).isEqualTo(LEAST); 72 } 73 assertCastFails(long value)74 private static void assertCastFails(long value) { 75 try { 76 UnsignedBytes.checkedCast(value); 77 fail("Cast to byte should have failed: " + value); 78 } catch (IllegalArgumentException ex) { 79 assertWithMessage(value + " not found in exception text: " + ex.getMessage()) 80 .that(ex.getMessage().contains(String.valueOf(value))) 81 .isTrue(); 82 } 83 } 84 testCompare()85 public void testCompare() { 86 // This is the only ordering for primitives that does not have a 87 // corresponding Comparable wrapper in java.lang. 88 for (int i = 0; i < VALUES.length; i++) { 89 for (int j = 0; j < VALUES.length; j++) { 90 byte x = VALUES[i]; 91 byte y = VALUES[j]; 92 // note: spec requires only that the sign is the same 93 assertWithMessage(x + ", " + y) 94 .that(Math.signum(Ints.compare(i, j))) 95 .isEqualTo(Math.signum(UnsignedBytes.compare(x, y))); 96 } 97 } 98 } 99 testMax_noArgs()100 public void testMax_noArgs() { 101 assertThrows(IllegalArgumentException.class, () -> UnsignedBytes.max()); 102 } 103 testMax()104 public void testMax() { 105 assertThat(UnsignedBytes.max(LEAST)).isEqualTo(LEAST); 106 assertThat(UnsignedBytes.max(GREATEST)).isEqualTo(GREATEST); 107 assertThat(UnsignedBytes.max((byte) 0, (byte) -128, (byte) -1, (byte) 127, (byte) 1)) 108 .isEqualTo((byte) 255); 109 } 110 testMin_noArgs()111 public void testMin_noArgs() { 112 assertThrows(IllegalArgumentException.class, () -> UnsignedBytes.min()); 113 } 114 testMin()115 public void testMin() { 116 assertThat(UnsignedBytes.min(LEAST)).isEqualTo(LEAST); 117 assertThat(UnsignedBytes.min(GREATEST)).isEqualTo(GREATEST); 118 assertThat(UnsignedBytes.min((byte) 0, (byte) -128, (byte) -1, (byte) 127, (byte) 1)) 119 .isEqualTo((byte) 0); 120 assertThat(UnsignedBytes.min((byte) -1, (byte) 127, (byte) 1, (byte) -128, (byte) 0)) 121 .isEqualTo((byte) 0); 122 } 123 assertParseFails(String value)124 private static void assertParseFails(String value) { 125 try { 126 UnsignedBytes.parseUnsignedByte(value); 127 fail(); 128 } catch (NumberFormatException expected) { 129 } 130 } 131 assertParseFails(String value, int radix)132 private static void assertParseFails(String value, int radix) { 133 try { 134 UnsignedBytes.parseUnsignedByte(value, radix); 135 fail(); 136 } catch (NumberFormatException expected) { 137 } 138 } 139 testParseUnsignedByte()140 public void testParseUnsignedByte() { 141 // We can easily afford to test this exhaustively. 142 for (int i = 0; i <= 0xff; i++) { 143 assertThat(UnsignedBytes.parseUnsignedByte(Integer.toString(i))).isEqualTo((byte) i); 144 } 145 assertParseFails("1000"); 146 assertParseFails("-1"); 147 assertParseFails("-128"); 148 assertParseFails("256"); 149 } 150 testMaxValue()151 public void testMaxValue() { 152 assertThat(UnsignedBytes.compare(UnsignedBytes.MAX_VALUE, (byte) (UnsignedBytes.MAX_VALUE + 1))) 153 .isGreaterThan(0); 154 } 155 testParseUnsignedByteWithRadix()156 public void testParseUnsignedByteWithRadix() throws NumberFormatException { 157 // We can easily afford to test this exhaustively. 158 for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { 159 for (int i = 0; i <= 0xff; i++) { 160 assertThat(UnsignedBytes.parseUnsignedByte(Integer.toString(i, radix), radix)) 161 .isEqualTo((byte) i); 162 } 163 assertParseFails(Integer.toString(1000, radix), radix); 164 assertParseFails(Integer.toString(-1, radix), radix); 165 assertParseFails(Integer.toString(-128, radix), radix); 166 assertParseFails(Integer.toString(256, radix), radix); 167 } 168 } 169 testParseUnsignedByteThrowsExceptionForInvalidRadix()170 public void testParseUnsignedByteThrowsExceptionForInvalidRadix() { 171 // Valid radix values are Character.MIN_RADIX to Character.MAX_RADIX, 172 // inclusive. 173 assertThrows( 174 NumberFormatException.class, 175 () -> UnsignedBytes.parseUnsignedByte("0", Character.MIN_RADIX - 1)); 176 177 assertThrows( 178 NumberFormatException.class, 179 () -> UnsignedBytes.parseUnsignedByte("0", Character.MAX_RADIX + 1)); 180 181 // The radix is used as an array index, so try a negative value. 182 assertThrows(NumberFormatException.class, () -> UnsignedBytes.parseUnsignedByte("0", -1)); 183 } 184 testToString()185 public void testToString() { 186 // We can easily afford to test this exhaustively. 187 for (int i = 0; i <= 0xff; i++) { 188 assertThat(UnsignedBytes.toString((byte) i)).isEqualTo(Integer.toString(i)); 189 } 190 } 191 testToStringWithRadix()192 public void testToStringWithRadix() { 193 // We can easily afford to test this exhaustively. 194 for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { 195 for (int i = 0; i <= 0xff; i++) { 196 assertThat(UnsignedBytes.toString((byte) i, radix)).isEqualTo(Integer.toString(i, radix)); 197 } 198 } 199 } 200 testJoin()201 public void testJoin() { 202 assertThat(UnsignedBytes.join(",", new byte[] {})).isEmpty(); 203 assertThat(UnsignedBytes.join(",", new byte[] {(byte) 1})).isEqualTo("1"); 204 assertThat(UnsignedBytes.join(",", (byte) 1, (byte) 2)).isEqualTo("1,2"); 205 assertThat(UnsignedBytes.join("", (byte) 1, (byte) 2, (byte) 3)).isEqualTo("123"); 206 assertThat(UnsignedBytes.join(",", (byte) 128, (byte) -1)).isEqualTo("128,255"); 207 } 208 unsafeComparatorClassName()209 private static String unsafeComparatorClassName() { 210 return UnsignedBytes.LexicographicalComparatorHolder.class.getName() + "$UnsafeComparator"; 211 } 212 unsafeComparatorAvailable()213 private static boolean unsafeComparatorAvailable() { 214 // See Java Puzzler #44 215 // Use reflection instead of catching NoClassDefFoundError 216 try { 217 Class.forName(unsafeComparatorClassName()); 218 return true; 219 } catch (Error | ClassNotFoundException tolerable) { 220 /* 221 * We're probably running on Android. 222 * 223 * A note on exception types: 224 * 225 * Android API level 10 throws ExceptionInInitializerError the first time and 226 * ClassNotFoundException thereafter. 227 * 228 * Android API level 26 and JVM8 both let our Error propagate directly the first time and 229 * throw NoClassDefFoundError thereafter. This is the proper behavior according to the spec. 230 * See https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.4.2 (steps #11 and 231 * #5). 232 * 233 * Note that that "first time" might happen in a test other than 234 * testLexicographicalComparatorChoice! 235 */ 236 return false; 237 } 238 } 239 testLexicographicalComparatorChoice()240 public void testLexicographicalComparatorChoice() throws Exception { 241 Comparator<byte[]> defaultComparator = UnsignedBytes.lexicographicalComparator(); 242 assertThat(defaultComparator).isNotNull(); 243 assertThat(UnsignedBytes.lexicographicalComparator()).isSameInstanceAs(defaultComparator); 244 if (unsafeComparatorAvailable()) { 245 assertThat(Class.forName(unsafeComparatorClassName())) 246 .isSameInstanceAs(defaultComparator.getClass()); 247 } else { 248 assertThat(UnsignedBytes.lexicographicalComparatorJavaImpl()) 249 .isSameInstanceAs(defaultComparator); 250 } 251 } 252 testLexicographicalComparator()253 public void testLexicographicalComparator() { 254 List<byte[]> ordered = 255 Arrays.asList( 256 new byte[] {}, 257 new byte[] {LEAST}, 258 new byte[] {LEAST, LEAST}, 259 new byte[] {LEAST, (byte) 1}, 260 new byte[] {(byte) 1}, 261 new byte[] {(byte) 1, LEAST}, 262 new byte[] {GREATEST, GREATEST - (byte) 1}, 263 new byte[] {GREATEST, GREATEST}, 264 new byte[] {GREATEST, GREATEST, GREATEST}); 265 266 // The Unsafe implementation if it's available. Otherwise, the Java implementation. 267 Comparator<byte[]> comparator = UnsignedBytes.lexicographicalComparator(); 268 Helpers.testComparator(comparator, ordered); 269 assertThat(SerializableTester.reserialize(comparator)).isSameInstanceAs(comparator); 270 271 // The Java implementation. 272 Comparator<byte[]> javaImpl = UnsignedBytes.lexicographicalComparatorJavaImpl(); 273 Helpers.testComparator(javaImpl, ordered); 274 assertThat(SerializableTester.reserialize(javaImpl)).isSameInstanceAs(javaImpl); 275 } 276 277 @SuppressWarnings("unchecked") testLexicographicalComparatorLongInputs()278 public void testLexicographicalComparatorLongInputs() { 279 Random rnd = new Random(); 280 for (Comparator<byte[]> comparator : 281 Arrays.asList( 282 UnsignedBytes.lexicographicalComparator(), 283 UnsignedBytes.lexicographicalComparatorJavaImpl())) { 284 for (int trials = 10; trials-- > 0; ) { 285 byte[] left = new byte[1 + rnd.nextInt(32)]; 286 rnd.nextBytes(left); 287 byte[] right = left.clone(); 288 assertThat(comparator.compare(left, right)).isEqualTo(0); 289 int i = rnd.nextInt(left.length); 290 left[i] ^= (byte) (1 + rnd.nextInt(255)); 291 assertThat(comparator.compare(left, right)).isNotEqualTo(0); 292 assertThat(UnsignedBytes.compare(left[i], right[i]) > 0) 293 .isEqualTo(comparator.compare(left, right) > 0); 294 } 295 } 296 } 297 testSort()298 public void testSort() { 299 testSort(new byte[] {}, new byte[] {}); 300 testSort(new byte[] {2}, new byte[] {2}); 301 testSort(new byte[] {2, 1, 0}, new byte[] {0, 1, 2}); 302 testSort(new byte[] {2, GREATEST, 1, LEAST}, new byte[] {LEAST, 1, 2, GREATEST}); 303 } 304 testSort(byte[] input, byte[] expected)305 static void testSort(byte[] input, byte[] expected) { 306 input = Arrays.copyOf(input, input.length); 307 UnsignedBytes.sort(input); 308 assertThat(input).isEqualTo(expected); 309 } 310 testSort(byte[] input, int from, int to, byte[] expected)311 static void testSort(byte[] input, int from, int to, byte[] expected) { 312 input = Arrays.copyOf(input, input.length); 313 UnsignedBytes.sort(input, from, to); 314 assertThat(input).isEqualTo(expected); 315 } 316 testSortIndexed()317 public void testSortIndexed() { 318 testSort(new byte[] {}, 0, 0, new byte[] {}); 319 testSort(new byte[] {2}, 0, 1, new byte[] {2}); 320 testSort(new byte[] {2, 1, 0}, 0, 2, new byte[] {1, 2, 0}); 321 testSort(new byte[] {2, GREATEST, 1, LEAST}, 1, 4, new byte[] {2, LEAST, 1, GREATEST}); 322 } 323 testSortDescending()324 public void testSortDescending() { 325 testSortDescending(new byte[] {}, new byte[] {}); 326 testSortDescending(new byte[] {1}, new byte[] {1}); 327 testSortDescending(new byte[] {1, 2}, new byte[] {2, 1}); 328 testSortDescending(new byte[] {1, 3, 1}, new byte[] {3, 1, 1}); 329 testSortDescending( 330 new byte[] {GREATEST - 1, 1, GREATEST - 2, 2}, 331 new byte[] {GREATEST - 1, GREATEST - 2, 2, 1}); 332 } 333 testSortDescending(byte[] input, byte[] expectedOutput)334 private static void testSortDescending(byte[] input, byte[] expectedOutput) { 335 input = Arrays.copyOf(input, input.length); 336 UnsignedBytes.sortDescending(input); 337 assertThat(input).isEqualTo(expectedOutput); 338 } 339 testSortDescending( byte[] input, int fromIndex, int toIndex, byte[] expectedOutput)340 private static void testSortDescending( 341 byte[] input, int fromIndex, int toIndex, byte[] expectedOutput) { 342 input = Arrays.copyOf(input, input.length); 343 UnsignedBytes.sortDescending(input, fromIndex, toIndex); 344 assertThat(input).isEqualTo(expectedOutput); 345 } 346 testSortDescendingIndexed()347 public void testSortDescendingIndexed() { 348 testSortDescending(new byte[] {}, 0, 0, new byte[] {}); 349 testSortDescending(new byte[] {1}, 0, 1, new byte[] {1}); 350 testSortDescending(new byte[] {1, 2}, 0, 2, new byte[] {2, 1}); 351 testSortDescending(new byte[] {1, 3, 1}, 0, 2, new byte[] {3, 1, 1}); 352 testSortDescending(new byte[] {1, 3, 1}, 0, 1, new byte[] {1, 3, 1}); 353 testSortDescending( 354 new byte[] {GREATEST - 1, 1, GREATEST - 2, 2}, 355 1, 356 3, 357 new byte[] {GREATEST - 1, GREATEST - 2, 1, 2}); 358 } 359 testNulls()360 public void testNulls() { 361 new NullPointerTester().testAllPublicStaticMethods(UnsignedBytes.class); 362 } 363 } 364