• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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