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 com.google.common.annotations.GwtCompatible;
20import com.google.common.annotations.GwtIncompatible;
21import com.google.common.collect.testing.Helpers;
22import com.google.common.testing.NullPointerTester;
23import com.google.common.testing.SerializableTester;
24
25import junit.framework.TestCase;
26
27import java.util.Arrays;
28import java.util.Collection;
29import java.util.Collections;
30import java.util.Comparator;
31import java.util.List;
32
33/**
34 * Unit test for {@link Chars}.
35 *
36 * @author Kevin Bourrillion
37 */
38@GwtCompatible(emulated = true)
39@SuppressWarnings("cast") // redundant casts are intentional and harmless
40public class CharsTest extends TestCase {
41  private static final char[] EMPTY = {};
42  private static final char[] ARRAY1 = {(char) 1};
43  private static final char[] ARRAY234
44      = {(char) 2, (char) 3, (char) 4};
45
46  private static final char LEAST = Character.MIN_VALUE;
47  private static final char GREATEST = Character.MAX_VALUE;
48
49  private static final char[] VALUES =
50      {LEAST, 'a', '\u00e0', '\udcaa', GREATEST};
51
52  public void testHashCode() {
53    for (char value : VALUES) {
54      assertEquals(((Character) value).hashCode(), Chars.hashCode(value));
55    }
56  }
57
58  public void testCheckedCast() {
59    for (char value : VALUES) {
60      assertEquals(value, Chars.checkedCast((long) value));
61    }
62    assertCastFails(GREATEST + 1L);
63    assertCastFails(LEAST - 1L);
64    assertCastFails(Long.MAX_VALUE);
65    assertCastFails(Long.MIN_VALUE);
66  }
67
68  public void testSaturatedCast() {
69    for (char value : VALUES) {
70      assertEquals(value, Chars.saturatedCast((long) value));
71    }
72    assertEquals(GREATEST, Chars.saturatedCast(GREATEST + 1L));
73    assertEquals(LEAST, Chars.saturatedCast(LEAST - 1L));
74    assertEquals(GREATEST, Chars.saturatedCast(Long.MAX_VALUE));
75    assertEquals(LEAST, Chars.saturatedCast(Long.MIN_VALUE));
76  }
77
78  private void assertCastFails(long value) {
79    try {
80      Chars.checkedCast(value);
81      fail("Cast to char should have failed: " + value);
82    } catch (IllegalArgumentException ex) {
83      assertTrue(value + " not found in exception text: " + ex.getMessage(),
84          ex.getMessage().contains(String.valueOf(value)));
85    }
86  }
87
88  public void testCompare() {
89    for (char x : VALUES) {
90      for (char y : VALUES) {
91        // note: spec requires only that the sign is the same
92        assertEquals(x + ", " + y,
93                     Character.valueOf(x).compareTo(y),
94                     Chars.compare(x, y));
95      }
96    }
97  }
98
99  public void testContains() {
100    assertFalse(Chars.contains(EMPTY, (char) 1));
101    assertFalse(Chars.contains(ARRAY1, (char) 2));
102    assertFalse(Chars.contains(ARRAY234, (char) 1));
103    assertTrue(Chars.contains(new char[] {(char) -1}, (char) -1));
104    assertTrue(Chars.contains(ARRAY234, (char) 2));
105    assertTrue(Chars.contains(ARRAY234, (char) 3));
106    assertTrue(Chars.contains(ARRAY234, (char) 4));
107  }
108
109  public void testIndexOf() {
110    assertEquals(-1, Chars.indexOf(EMPTY, (char) 1));
111    assertEquals(-1, Chars.indexOf(ARRAY1, (char) 2));
112    assertEquals(-1, Chars.indexOf(ARRAY234, (char) 1));
113    assertEquals(0, Chars.indexOf(
114        new char[] {(char) -1}, (char) -1));
115    assertEquals(0, Chars.indexOf(ARRAY234, (char) 2));
116    assertEquals(1, Chars.indexOf(ARRAY234, (char) 3));
117    assertEquals(2, Chars.indexOf(ARRAY234, (char) 4));
118    assertEquals(1, Chars.indexOf(
119        new char[] { (char) 2, (char) 3, (char) 2, (char) 3 },
120        (char) 3));
121  }
122
123  public void testIndexOf_arrayTarget() {
124    assertEquals(0, Chars.indexOf(EMPTY, EMPTY));
125    assertEquals(0, Chars.indexOf(ARRAY234, EMPTY));
126    assertEquals(-1, Chars.indexOf(EMPTY, ARRAY234));
127    assertEquals(-1, Chars.indexOf(ARRAY234, ARRAY1));
128    assertEquals(-1, Chars.indexOf(ARRAY1, ARRAY234));
129    assertEquals(0, Chars.indexOf(ARRAY1, ARRAY1));
130    assertEquals(0, Chars.indexOf(ARRAY234, ARRAY234));
131    assertEquals(0, Chars.indexOf(
132        ARRAY234, new char[] { (char) 2, (char) 3 }));
133    assertEquals(1, Chars.indexOf(
134        ARRAY234, new char[] { (char) 3, (char) 4 }));
135    assertEquals(1, Chars.indexOf(ARRAY234, new char[] { (char) 3 }));
136    assertEquals(2, Chars.indexOf(ARRAY234, new char[] { (char) 4 }));
137    assertEquals(1, Chars.indexOf(new char[] { (char) 2, (char) 3,
138        (char) 3, (char) 3, (char) 3 },
139        new char[] { (char) 3 }
140    ));
141    assertEquals(2, Chars.indexOf(
142        new char[] { (char) 2, (char) 3, (char) 2,
143            (char) 3, (char) 4, (char) 2, (char) 3},
144        new char[] { (char) 2, (char) 3, (char) 4}
145    ));
146    assertEquals(1, Chars.indexOf(
147        new char[] { (char) 2, (char) 2, (char) 3,
148            (char) 4, (char) 2, (char) 3, (char) 4},
149        new char[] { (char) 2, (char) 3, (char) 4}
150    ));
151    assertEquals(-1, Chars.indexOf(
152        new char[] { (char) 4, (char) 3, (char) 2},
153        new char[] { (char) 2, (char) 3, (char) 4}
154    ));
155  }
156
157  public void testLastIndexOf() {
158    assertEquals(-1, Chars.lastIndexOf(EMPTY, (char) 1));
159    assertEquals(-1, Chars.lastIndexOf(ARRAY1, (char) 2));
160    assertEquals(-1, Chars.lastIndexOf(ARRAY234, (char) 1));
161    assertEquals(0, Chars.lastIndexOf(
162        new char[] {(char) -1}, (char) -1));
163    assertEquals(0, Chars.lastIndexOf(ARRAY234, (char) 2));
164    assertEquals(1, Chars.lastIndexOf(ARRAY234, (char) 3));
165    assertEquals(2, Chars.lastIndexOf(ARRAY234, (char) 4));
166    assertEquals(3, Chars.lastIndexOf(
167        new char[] { (char) 2, (char) 3, (char) 2, (char) 3 },
168        (char) 3));
169  }
170
171  public void testMax_noArgs() {
172    try {
173      Chars.max();
174      fail();
175    } catch (IllegalArgumentException expected) {
176    }
177  }
178
179  public void testMax() {
180    assertEquals(LEAST, Chars.max(LEAST));
181    assertEquals(GREATEST, Chars.max(GREATEST));
182    assertEquals((char) 9, Chars.max(
183        (char) 8, (char) 6, (char) 7,
184        (char) 5, (char) 3, (char) 0, (char) 9));
185  }
186
187  public void testMin_noArgs() {
188    try {
189      Chars.min();
190      fail();
191    } catch (IllegalArgumentException expected) {
192    }
193  }
194
195  public void testMin() {
196    assertEquals(LEAST, Chars.min(LEAST));
197    assertEquals(GREATEST, Chars.min(GREATEST));
198    assertEquals((char) 0, Chars.min(
199        (char) 8, (char) 6, (char) 7,
200        (char) 5, (char) 3, (char) 0, (char) 9));
201  }
202
203  public void testConcat() {
204    assertTrue(Arrays.equals(EMPTY, Chars.concat()));
205    assertTrue(Arrays.equals(EMPTY, Chars.concat(EMPTY)));
206    assertTrue(Arrays.equals(EMPTY, Chars.concat(EMPTY, EMPTY, EMPTY)));
207    assertTrue(Arrays.equals(ARRAY1, Chars.concat(ARRAY1)));
208    assertNotSame(ARRAY1, Chars.concat(ARRAY1));
209    assertTrue(Arrays.equals(ARRAY1, Chars.concat(EMPTY, ARRAY1, EMPTY)));
210    assertTrue(Arrays.equals(
211        new char[] {(char) 1, (char) 1, (char) 1},
212        Chars.concat(ARRAY1, ARRAY1, ARRAY1)));
213    assertTrue(Arrays.equals(
214        new char[] {(char) 1, (char) 2, (char) 3, (char) 4},
215        Chars.concat(ARRAY1, ARRAY234)));
216  }
217
218  @GwtIncompatible("Chars.fromByteArray")
219  public void testFromByteArray() {
220    assertEquals('\u2345', Chars.fromByteArray(
221        new byte[] {0x23, 0x45, (byte) 0xDC}));
222    assertEquals('\uFEDC', Chars.fromByteArray(
223        new byte[] {(byte) 0xFE, (byte) 0xDC}));
224
225    try {
226      Chars.fromByteArray(new byte[Chars.BYTES - 1]);
227      fail();
228    } catch (IllegalArgumentException expected) {
229    }
230  }
231
232  @GwtIncompatible("Chars.fromBytes")
233  public void testFromBytes() {
234    assertEquals('\u2345', Chars.fromBytes((byte) 0x23, (byte) 0x45));
235    assertEquals('\uFEDC', Chars.fromBytes((byte) 0xFE, (byte) 0xDC));
236  }
237
238  @GwtIncompatible("Chars.fromByteArray, Chars.toByteArray")
239  public void testByteArrayRoundTrips() {
240    char c = 0;
241    for (int hi = 0; hi < 256; hi++) {
242      for (int lo = 0; lo < 256; lo++) {
243        char result = Chars.fromByteArray(new byte[]{(byte) hi, (byte) lo});
244        assertEquals(String.format("hi=%s, lo=%s, expected=%s, result=%s",
245            hi, lo, (int) c, (int) result), c, result);
246
247        byte[] bytes = Chars.toByteArray(c);
248        assertEquals((byte) hi, bytes[0]);
249        assertEquals((byte) lo, bytes[1]);
250
251        c++;
252      }
253    }
254    assertEquals((char) 0, c); // sanity check
255
256    try {
257      Chars.fromByteArray(new byte[] {0x11});
258      fail();
259    } catch (IllegalArgumentException expected) {
260    }
261  }
262
263  public void testEnsureCapacity() {
264    assertSame(EMPTY, Chars.ensureCapacity(EMPTY, 0, 1));
265    assertSame(ARRAY1, Chars.ensureCapacity(ARRAY1, 0, 1));
266    assertSame(ARRAY1, Chars.ensureCapacity(ARRAY1, 1, 1));
267    assertTrue(Arrays.equals(
268        new char[] {(char) 1, (char) 0, (char) 0},
269        Chars.ensureCapacity(ARRAY1, 2, 1)));
270  }
271
272  public void testEnsureCapacity_fail() {
273    try {
274      Chars.ensureCapacity(ARRAY1, -1, 1);
275      fail();
276    } catch (IllegalArgumentException expected) {
277    }
278    try {
279      // notice that this should even fail when no growth was needed
280      Chars.ensureCapacity(ARRAY1, 1, -1);
281      fail();
282    } catch (IllegalArgumentException expected) {
283    }
284  }
285
286  public void testJoin() {
287    assertEquals("", Chars.join(",", EMPTY));
288    assertEquals("1", Chars.join(",", '1'));
289    assertEquals("1,2", Chars.join(",", '1', '2'));
290    assertEquals("123", Chars.join("", '1', '2', '3'));
291  }
292
293  public void testLexicographicalComparator() {
294    List<char[]> ordered = Arrays.asList(
295        new char[] {},
296        new char[] {LEAST},
297        new char[] {LEAST, LEAST},
298        new char[] {LEAST, (char) 1},
299        new char[] {(char) 1},
300        new char[] {(char) 1, LEAST},
301        new char[] {GREATEST, GREATEST - (char) 1},
302        new char[] {GREATEST, GREATEST},
303        new char[] {GREATEST, GREATEST, GREATEST});
304
305    Comparator<char[]> comparator = Chars.lexicographicalComparator();
306    Helpers.testComparator(comparator, ordered);
307  }
308
309  @GwtIncompatible("SerializableTester")
310  public void testLexicographicalComparatorSerializable() {
311    Comparator<char[]> comparator = Chars.lexicographicalComparator();
312    assertSame(comparator, SerializableTester.reserialize(comparator));
313  }
314
315  public void testToArray() {
316    // need explicit type parameter to avoid javac warning!?
317    List<Character> none = Arrays.<Character>asList();
318    assertTrue(Arrays.equals(EMPTY, Chars.toArray(none)));
319
320    List<Character> one = Arrays.asList((char) 1);
321    assertTrue(Arrays.equals(ARRAY1, Chars.toArray(one)));
322
323    char[] array = {(char) 0, (char) 1, 'A'};
324
325    List<Character> three = Arrays.asList((char) 0, (char) 1, 'A');
326    assertTrue(Arrays.equals(array, Chars.toArray(three)));
327
328    assertTrue(Arrays.equals(array, Chars.toArray(Chars.asList(array))));
329  }
330
331  public void testToArray_threadSafe() {
332    for (int delta : new int[] { +1, 0, -1 }) {
333      for (int i = 0; i < VALUES.length; i++) {
334        List<Character> list = Chars.asList(VALUES).subList(0, i);
335        Collection<Character> misleadingSize =
336            Helpers.misleadingSizeCollection(delta);
337        misleadingSize.addAll(list);
338        char[] arr = Chars.toArray(misleadingSize);
339        assertEquals(i, arr.length);
340        for (int j = 0; j < i; j++) {
341          assertEquals(VALUES[j], arr[j]);
342        }
343      }
344    }
345  }
346
347  public void testToArray_withNull() {
348    List<Character> list = Arrays.asList((char) 0, (char) 1, null);
349    try {
350      Chars.toArray(list);
351      fail();
352    } catch (NullPointerException expected) {
353    }
354  }
355
356  public void testAsList_isAView() {
357    char[] array = {(char) 0, (char) 1};
358    List<Character> list = Chars.asList(array);
359    list.set(0, (char) 2);
360    assertTrue(Arrays.equals(new char[] {(char) 2, (char) 1}, array));
361    array[1] = (char) 3;
362    assertEquals(Arrays.asList((char) 2, (char) 3), list);
363  }
364
365  public void testAsList_toArray_roundTrip() {
366    char[] array = { (char) 0, (char) 1, (char) 2 };
367    List<Character> list = Chars.asList(array);
368    char[] newArray = Chars.toArray(list);
369
370    // Make sure it returned a copy
371    list.set(0, (char) 4);
372    assertTrue(Arrays.equals(
373        new char[] { (char) 0, (char) 1, (char) 2 }, newArray));
374    newArray[1] = (char) 5;
375    assertEquals((char) 1, (char) list.get(1));
376  }
377
378  // This test stems from a real bug found by andrewk
379  public void testAsList_subList_toArray_roundTrip() {
380    char[] array = { (char) 0, (char) 1, (char) 2, (char) 3 };
381    List<Character> list = Chars.asList(array);
382    assertTrue(Arrays.equals(new char[] { (char) 1, (char) 2 },
383        Chars.toArray(list.subList(1, 3))));
384    assertTrue(Arrays.equals(new char[] {},
385        Chars.toArray(list.subList(2, 2))));
386  }
387
388  public void testAsListEmpty() {
389    assertSame(Collections.emptyList(), Chars.asList(EMPTY));
390  }
391
392  @GwtIncompatible("NullPointerTester")
393  public void testNulls() {
394    new NullPointerTester().testAllPublicStaticMethods(Chars.class);
395  }
396}
397