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
17package com.google.common.primitives;
18
19import static java.lang.Long.MAX_VALUE;
20import static java.lang.Long.MIN_VALUE;
21
22import com.google.common.annotations.GwtCompatible;
23import com.google.common.annotations.GwtIncompatible;
24import com.google.common.base.Converter;
25import com.google.common.collect.testing.Helpers;
26import com.google.common.testing.NullPointerTester;
27import com.google.common.testing.SerializableTester;
28
29import junit.framework.TestCase;
30
31import java.math.BigInteger;
32import java.util.Arrays;
33import java.util.Collection;
34import java.util.Collections;
35import java.util.Comparator;
36import java.util.List;
37import java.util.Random;
38
39/**
40 * Unit test for {@link Longs}.
41 *
42 * @author Kevin Bourrillion
43 */
44@GwtCompatible(emulated = true)
45@SuppressWarnings("cast") // redundant casts are intentional and harmless
46public class LongsTest extends TestCase {
47  private static final long[] EMPTY = {};
48  private static final long[] ARRAY1 = {(long) 1};
49  private static final long[] ARRAY234
50      = {(long) 2, (long) 3, (long) 4};
51
52  private static final long[] VALUES =
53      { MIN_VALUE, (long) -1, (long) 0, (long) 1, MAX_VALUE };
54
55  @GwtIncompatible("Long.hashCode returns different values in GWT.")
56  public void testHashCode() {
57    for (long value : VALUES) {
58      assertEquals("hashCode for " + value,
59          ((Long) value).hashCode(), Longs.hashCode(value));
60    }
61  }
62
63  public void testCompare() {
64    for (long x : VALUES) {
65      for (long y : VALUES) {
66        // note: spec requires only that the sign is the same
67        assertEquals(x + ", " + y,
68                     Long.valueOf(x).compareTo(y),
69                     Longs.compare(x, y));
70      }
71    }
72  }
73
74  public void testContains() {
75    assertFalse(Longs.contains(EMPTY, (long) 1));
76    assertFalse(Longs.contains(ARRAY1, (long) 2));
77    assertFalse(Longs.contains(ARRAY234, (long) 1));
78    assertTrue(Longs.contains(new long[] {(long) -1}, (long) -1));
79    assertTrue(Longs.contains(ARRAY234, (long) 2));
80    assertTrue(Longs.contains(ARRAY234, (long) 3));
81    assertTrue(Longs.contains(ARRAY234, (long) 4));
82  }
83
84  public void testIndexOf() {
85    assertEquals(-1, Longs.indexOf(EMPTY, (long) 1));
86    assertEquals(-1, Longs.indexOf(ARRAY1, (long) 2));
87    assertEquals(-1, Longs.indexOf(ARRAY234, (long) 1));
88    assertEquals(0, Longs.indexOf(
89        new long[] {(long) -1}, (long) -1));
90    assertEquals(0, Longs.indexOf(ARRAY234, (long) 2));
91    assertEquals(1, Longs.indexOf(ARRAY234, (long) 3));
92    assertEquals(2, Longs.indexOf(ARRAY234, (long) 4));
93    assertEquals(1, Longs.indexOf(
94        new long[] { (long) 2, (long) 3, (long) 2, (long) 3 },
95        (long) 3));
96  }
97
98  public void testIndexOf_arrayTarget() {
99    assertEquals(0, Longs.indexOf(EMPTY, EMPTY));
100    assertEquals(0, Longs.indexOf(ARRAY234, EMPTY));
101    assertEquals(-1, Longs.indexOf(EMPTY, ARRAY234));
102    assertEquals(-1, Longs.indexOf(ARRAY234, ARRAY1));
103    assertEquals(-1, Longs.indexOf(ARRAY1, ARRAY234));
104    assertEquals(0, Longs.indexOf(ARRAY1, ARRAY1));
105    assertEquals(0, Longs.indexOf(ARRAY234, ARRAY234));
106    assertEquals(0, Longs.indexOf(
107        ARRAY234, new long[] { (long) 2, (long) 3 }));
108    assertEquals(1, Longs.indexOf(
109        ARRAY234, new long[] { (long) 3, (long) 4 }));
110    assertEquals(1, Longs.indexOf(ARRAY234, new long[] { (long) 3 }));
111    assertEquals(2, Longs.indexOf(ARRAY234, new long[] { (long) 4 }));
112    assertEquals(1, Longs.indexOf(new long[] { (long) 2, (long) 3,
113        (long) 3, (long) 3, (long) 3 },
114        new long[] { (long) 3 }
115    ));
116    assertEquals(2, Longs.indexOf(
117        new long[] { (long) 2, (long) 3, (long) 2,
118            (long) 3, (long) 4, (long) 2, (long) 3},
119        new long[] { (long) 2, (long) 3, (long) 4}
120    ));
121    assertEquals(1, Longs.indexOf(
122        new long[] { (long) 2, (long) 2, (long) 3,
123            (long) 4, (long) 2, (long) 3, (long) 4},
124        new long[] { (long) 2, (long) 3, (long) 4}
125    ));
126    assertEquals(-1, Longs.indexOf(
127        new long[] { (long) 4, (long) 3, (long) 2},
128        new long[] { (long) 2, (long) 3, (long) 4}
129    ));
130  }
131
132  public void testLastIndexOf() {
133    assertEquals(-1, Longs.lastIndexOf(EMPTY, (long) 1));
134    assertEquals(-1, Longs.lastIndexOf(ARRAY1, (long) 2));
135    assertEquals(-1, Longs.lastIndexOf(ARRAY234, (long) 1));
136    assertEquals(0, Longs.lastIndexOf(
137        new long[] {(long) -1}, (long) -1));
138    assertEquals(0, Longs.lastIndexOf(ARRAY234, (long) 2));
139    assertEquals(1, Longs.lastIndexOf(ARRAY234, (long) 3));
140    assertEquals(2, Longs.lastIndexOf(ARRAY234, (long) 4));
141    assertEquals(3, Longs.lastIndexOf(
142        new long[] { (long) 2, (long) 3, (long) 2, (long) 3 },
143        (long) 3));
144  }
145
146  public void testMax_noArgs() {
147    try {
148      Longs.max();
149      fail();
150    } catch (IllegalArgumentException expected) {
151    }
152  }
153
154  public void testMax() {
155    assertEquals(MIN_VALUE, Longs.max(MIN_VALUE));
156    assertEquals(MAX_VALUE, Longs.max(MAX_VALUE));
157    assertEquals((long) 9, Longs.max(
158        (long) 8, (long) 6, (long) 7,
159        (long) 5, (long) 3, (long) 0, (long) 9));
160  }
161
162  public void testMin_noArgs() {
163    try {
164      Longs.min();
165      fail();
166    } catch (IllegalArgumentException expected) {
167    }
168  }
169
170  public void testMin() {
171    assertEquals(MIN_VALUE, Longs.min(MIN_VALUE));
172    assertEquals(MAX_VALUE, Longs.min(MAX_VALUE));
173    assertEquals((long) 0, Longs.min(
174        (long) 8, (long) 6, (long) 7,
175        (long) 5, (long) 3, (long) 0, (long) 9));
176  }
177
178  public void testConcat() {
179    assertTrue(Arrays.equals(EMPTY, Longs.concat()));
180    assertTrue(Arrays.equals(EMPTY, Longs.concat(EMPTY)));
181    assertTrue(Arrays.equals(EMPTY, Longs.concat(EMPTY, EMPTY, EMPTY)));
182    assertTrue(Arrays.equals(ARRAY1, Longs.concat(ARRAY1)));
183    assertNotSame(ARRAY1, Longs.concat(ARRAY1));
184    assertTrue(Arrays.equals(ARRAY1, Longs.concat(EMPTY, ARRAY1, EMPTY)));
185    assertTrue(Arrays.equals(
186        new long[] {(long) 1, (long) 1, (long) 1},
187        Longs.concat(ARRAY1, ARRAY1, ARRAY1)));
188    assertTrue(Arrays.equals(
189        new long[] {(long) 1, (long) 2, (long) 3, (long) 4},
190        Longs.concat(ARRAY1, ARRAY234)));
191  }
192
193  private static void assertByteArrayEquals(byte[] expected, byte[] actual) {
194    assertTrue(
195        "Expected: " + Arrays.toString(expected) + ", but got: " + Arrays.toString(actual),
196        Arrays.equals(expected, actual));
197  }
198
199  public void testToByteArray() {
200    assertByteArrayEquals(
201        new byte[] {0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19},
202        Longs.toByteArray(0x1213141516171819L));
203    assertByteArrayEquals(
204        new byte[] {
205            (byte) 0xFF, (byte) 0xEE, (byte) 0xDD, (byte) 0xCC,
206            (byte) 0xBB, (byte) 0xAA, (byte) 0x99, (byte) 0x88},
207        Longs.toByteArray(0xFFEEDDCCBBAA9988L));
208  }
209
210  public void testFromByteArray() {
211    assertEquals(0x1213141516171819L, Longs.fromByteArray(
212        new byte[] {0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x33}));
213    assertEquals(0xFFEEDDCCBBAA9988L, Longs.fromByteArray(
214        new byte[] {
215            (byte) 0xFF, (byte) 0xEE, (byte) 0xDD, (byte) 0xCC,
216            (byte) 0xBB, (byte) 0xAA, (byte) 0x99, (byte) 0x88}));
217
218    try {
219      Longs.fromByteArray(new byte[Longs.BYTES - 1]);
220      fail();
221    } catch (IllegalArgumentException expected) {
222    }
223  }
224
225  public void testFromBytes() {
226    assertEquals(0x1213141516171819L, Longs.fromBytes(
227        (byte) 0x12, (byte) 0x13, (byte) 0x14, (byte) 0x15,
228        (byte) 0x16, (byte) 0x17, (byte) 0x18, (byte) 0x19));
229    assertEquals(0xFFEEDDCCBBAA9988L, Longs.fromBytes(
230        (byte) 0xFF, (byte) 0xEE, (byte) 0xDD, (byte) 0xCC,
231        (byte) 0xBB, (byte) 0xAA, (byte) 0x99, (byte) 0x88));
232  }
233
234  public void testByteArrayRoundTrips() {
235    Random r = new Random(5);
236    byte[] b = new byte[Longs.BYTES];
237
238    // total overkill, but, it takes 0.1 sec so why not...
239    for (int i = 0; i < 10000; i++) {
240      long num = r.nextLong();
241      assertEquals(num, Longs.fromByteArray(Longs.toByteArray(num)));
242
243      r.nextBytes(b);
244      long value = Longs.fromByteArray(b);
245      assertTrue("" + value, Arrays.equals(b, Longs.toByteArray(value)));
246    }
247  }
248
249  public void testEnsureCapacity() {
250    assertSame(EMPTY, Longs.ensureCapacity(EMPTY, 0, 1));
251    assertSame(ARRAY1, Longs.ensureCapacity(ARRAY1, 0, 1));
252    assertSame(ARRAY1, Longs.ensureCapacity(ARRAY1, 1, 1));
253    assertTrue(Arrays.equals(
254        new long[] {(long) 1, (long) 0, (long) 0},
255        Longs.ensureCapacity(ARRAY1, 2, 1)));
256  }
257
258  public void testEnsureCapacity_fail() {
259    try {
260      Longs.ensureCapacity(ARRAY1, -1, 1);
261      fail();
262    } catch (IllegalArgumentException expected) {
263    }
264    try {
265      // notice that this should even fail when no growth was needed
266      Longs.ensureCapacity(ARRAY1, 1, -1);
267      fail();
268    } catch (IllegalArgumentException expected) {
269    }
270  }
271
272  public void testJoin() {
273    assertEquals("", Longs.join(",", EMPTY));
274    assertEquals("1", Longs.join(",", ARRAY1));
275    assertEquals("1,2", Longs.join(",", (long) 1, (long) 2));
276    assertEquals("123",
277        Longs.join("", (long) 1, (long) 2, (long) 3));
278  }
279
280  public void testLexicographicalComparator() {
281    List<long[]> ordered = Arrays.asList(
282        new long[] {},
283        new long[] {MIN_VALUE},
284        new long[] {MIN_VALUE, MIN_VALUE},
285        new long[] {MIN_VALUE, (long) 1},
286        new long[] {(long) 1},
287        new long[] {(long) 1, MIN_VALUE},
288        new long[] {MAX_VALUE, MAX_VALUE - (long) 1},
289        new long[] {MAX_VALUE, MAX_VALUE},
290        new long[] {MAX_VALUE, MAX_VALUE, MAX_VALUE});
291
292    Comparator<long[]> comparator = Longs.lexicographicalComparator();
293    Helpers.testComparator(comparator, ordered);
294  }
295
296  @GwtIncompatible("SerializableTester")
297  public void testLexicographicalComparatorSerializable() {
298    Comparator<long[]> comparator = Longs.lexicographicalComparator();
299    assertSame(comparator, SerializableTester.reserialize(comparator));
300  }
301
302  @GwtIncompatible("SerializableTester")
303  public void testStringConverterSerialization() {
304    SerializableTester.reserializeAndAssert(Longs.stringConverter());
305  }
306
307  public void testToArray() {
308    // need explicit type parameter to avoid javac warning!?
309    List<Long> none = Arrays.<Long>asList();
310    assertTrue(Arrays.equals(EMPTY, Longs.toArray(none)));
311
312    List<Long> one = Arrays.asList((long) 1);
313    assertTrue(Arrays.equals(ARRAY1, Longs.toArray(one)));
314
315    long[] array = {(long) 0, (long) 1, 0x0FF1C1AL};
316
317    List<Long> three = Arrays.asList((long) 0, (long) 1, 0x0FF1C1AL);
318    assertTrue(Arrays.equals(array, Longs.toArray(three)));
319
320    assertTrue(Arrays.equals(array, Longs.toArray(Longs.asList(array))));
321  }
322
323  public void testToArray_threadSafe() {
324    for (int delta : new int[] { +1, 0, -1 }) {
325      for (int i = 0; i < VALUES.length; i++) {
326        List<Long> list = Longs.asList(VALUES).subList(0, i);
327        Collection<Long> misleadingSize =
328            Helpers.misleadingSizeCollection(delta);
329        misleadingSize.addAll(list);
330        long[] arr = Longs.toArray(misleadingSize);
331        assertEquals(i, arr.length);
332        for (int j = 0; j < i; j++) {
333          assertEquals(VALUES[j], arr[j]);
334        }
335      }
336    }
337  }
338
339  public void testToArray_withNull() {
340    List<Long> list = Arrays.asList((long) 0, (long) 1, null);
341    try {
342      Longs.toArray(list);
343      fail();
344    } catch (NullPointerException expected) {
345    }
346  }
347
348  public void testToArray_withConversion() {
349    long[] array = {(long) 0, (long) 1, (long) 2};
350
351    List<Byte> bytes = Arrays.asList((byte) 0, (byte) 1, (byte) 2);
352    List<Short> shorts = Arrays.asList((short) 0, (short) 1, (short) 2);
353    List<Integer> ints = Arrays.asList(0, 1, 2);
354    List<Float> floats = Arrays.asList((float) 0, (float) 1, (float) 2);
355    List<Long> longs = Arrays.asList((long) 0, (long) 1, (long) 2);
356    List<Double> doubles = Arrays.asList((double) 0, (double) 1, (double) 2);
357
358    assertTrue(Arrays.equals(array, Longs.toArray(bytes)));
359    assertTrue(Arrays.equals(array, Longs.toArray(shorts)));
360    assertTrue(Arrays.equals(array, Longs.toArray(ints)));
361    assertTrue(Arrays.equals(array, Longs.toArray(floats)));
362    assertTrue(Arrays.equals(array, Longs.toArray(longs)));
363    assertTrue(Arrays.equals(array, Longs.toArray(doubles)));
364  }
365
366  public void testAsList_isAView() {
367    long[] array = {(long) 0, (long) 1};
368    List<Long> list = Longs.asList(array);
369    list.set(0, (long) 2);
370    assertTrue(Arrays.equals(new long[] {(long) 2, (long) 1}, array));
371    array[1] = (long) 3;
372    assertEquals(Arrays.asList((long) 2, (long) 3), list);
373  }
374
375  public void testAsList_toArray_roundTrip() {
376    long[] array = { (long) 0, (long) 1, (long) 2 };
377    List<Long> list = Longs.asList(array);
378    long[] newArray = Longs.toArray(list);
379
380    // Make sure it returned a copy
381    list.set(0, (long) 4);
382    assertTrue(Arrays.equals(
383        new long[] { (long) 0, (long) 1, (long) 2 }, newArray));
384    newArray[1] = (long) 5;
385    assertEquals((long) 1, (long) list.get(1));
386  }
387
388  // This test stems from a real bug found by andrewk
389  public void testAsList_subList_toArray_roundTrip() {
390    long[] array = { (long) 0, (long) 1, (long) 2, (long) 3 };
391    List<Long> list = Longs.asList(array);
392    assertTrue(Arrays.equals(new long[] { (long) 1, (long) 2 },
393        Longs.toArray(list.subList(1, 3))));
394    assertTrue(Arrays.equals(new long[] {},
395        Longs.toArray(list.subList(2, 2))));
396  }
397
398  public void testAsListEmpty() {
399    assertSame(Collections.emptyList(), Longs.asList(EMPTY));
400  }
401
402  @GwtIncompatible("NullPointerTester")
403  public void testNulls() {
404    new NullPointerTester().testAllPublicStaticMethods(Longs.class);
405  }
406
407  public void testStringConverter_convert() {
408    Converter<String, Long> converter = Longs.stringConverter();
409    assertEquals((Long) 1L, converter.convert("1"));
410    assertEquals((Long) 0L, converter.convert("0"));
411    assertEquals((Long) (-1L), converter.convert("-1"));
412    assertEquals((Long) 255L, converter.convert("0xff"));
413    assertEquals((Long) 255L, converter.convert("0xFF"));
414    assertEquals((Long) (-255L), converter.convert("-0xFF"));
415    assertEquals((Long) 255L, converter.convert("#0000FF"));
416    assertEquals((Long) 438L, converter.convert("0666"));
417  }
418
419  public void testStringConverter_convertError() {
420    try {
421      Longs.stringConverter().convert("notanumber");
422      fail();
423    } catch (NumberFormatException expected) {
424    }
425  }
426
427  public void testStringConverter_nullConversions() {
428    assertNull(Longs.stringConverter().convert(null));
429    assertNull(Longs.stringConverter().reverse().convert(null));
430  }
431
432  public void testStringConverter_reverse() {
433    Converter<String, Long> converter = Longs.stringConverter();
434    assertEquals("1", converter.reverse().convert(1L));
435    assertEquals("0", converter.reverse().convert(0L));
436    assertEquals("-1", converter.reverse().convert(-1L));
437    assertEquals("255", converter.reverse().convert(0xffL));
438    assertEquals("255", converter.reverse().convert(0xFFL));
439    assertEquals("-255", converter.reverse().convert(-0xFFL));
440    assertEquals("438", converter.reverse().convert(0666L));
441  }
442
443  @GwtIncompatible("NullPointerTester")
444  public void testStringConverter_nullPointerTester() throws Exception {
445    NullPointerTester tester = new NullPointerTester();
446    tester.testAllPublicInstanceMethods(Longs.stringConverter());
447  }
448
449  public void testTryParse() {
450    tryParseAndAssertEquals(0L, "0");
451    tryParseAndAssertEquals(0L, "-0");
452    tryParseAndAssertEquals(1L, "1");
453    tryParseAndAssertEquals(-1L, "-1");
454    tryParseAndAssertEquals(8900L, "8900");
455    tryParseAndAssertEquals(-8900L, "-8900");
456    tryParseAndAssertEquals(MAX_VALUE, Long.toString(MAX_VALUE));
457    tryParseAndAssertEquals(MIN_VALUE, Long.toString(MIN_VALUE));
458    assertNull(Longs.tryParse(""));
459    assertNull(Longs.tryParse("-"));
460    assertNull(Longs.tryParse("+1"));
461    assertNull(Longs.tryParse("999999999999999999999999"));
462    assertNull("Max long + 1",
463        Longs.tryParse(BigInteger.valueOf(MAX_VALUE).add(BigInteger.ONE).toString()));
464    assertNull("Max long * 10",
465        Longs.tryParse(BigInteger.valueOf(MAX_VALUE).multiply(BigInteger.TEN).toString()));
466    assertNull("Min long - 1",
467        Longs.tryParse(BigInteger.valueOf(MIN_VALUE).subtract(BigInteger.ONE).toString()));
468    assertNull("Min long * 10",
469        Longs.tryParse(BigInteger.valueOf(MIN_VALUE).multiply(BigInteger.TEN).toString()));
470    assertNull(Longs.tryParse("\u0662\u06f3"));
471  }
472
473  /**
474   * Applies {@link Longs#tryParse(String)} to the given string and asserts that
475   * the result is as expected.
476   */
477  private static void tryParseAndAssertEquals(Long expected, String value) {
478    assertEquals(expected, Longs.tryParse(value));
479  }
480}
481