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 java.lang.Double.NaN;
21 
22 import com.google.common.annotations.GwtCompatible;
23 import com.google.common.annotations.GwtIncompatible;
24 import com.google.common.base.Converter;
25 import com.google.common.collect.ImmutableList;
26 import com.google.common.collect.testing.Helpers;
27 import com.google.common.testing.NullPointerTester;
28 import com.google.common.testing.SerializableTester;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.Comparator;
33 import java.util.List;
34 import java.util.regex.Pattern;
35 import junit.framework.TestCase;
36 
37 /**
38  * Unit test for {@link Doubles}.
39  *
40  * @author Kevin Bourrillion
41  */
42 @GwtCompatible(emulated = true)
43 @SuppressWarnings("cast") // redundant casts are intentional and harmless
44 public class DoublesTest extends TestCase {
45   private static final double[] EMPTY = {};
46   private static final double[] ARRAY1 = {(double) 1};
47   private static final double[] ARRAY234 = {(double) 2, (double) 3, (double) 4};
48 
49   private static final double LEAST = Double.NEGATIVE_INFINITY;
50   private static final double GREATEST = Double.POSITIVE_INFINITY;
51 
52   private static final double[] NUMBERS =
53       new double[] {
54         LEAST,
55         -Double.MAX_VALUE,
56         -1.0,
57         -0.5,
58         -0.1,
59         -0.0,
60         0.0,
61         0.1,
62         0.5,
63         1.0,
64         Double.MAX_VALUE,
65         GREATEST,
66         Double.MIN_NORMAL,
67         -Double.MIN_NORMAL,
68         Double.MIN_VALUE,
69         -Double.MIN_VALUE,
70         Integer.MIN_VALUE,
71         Integer.MAX_VALUE,
72         Long.MIN_VALUE,
73         Long.MAX_VALUE
74       };
75 
76   private static final double[] VALUES = Doubles.concat(NUMBERS, new double[] {NaN});
77 
testHashCode()78   public void testHashCode() {
79     for (double value : VALUES) {
80       assertEquals(((Double) value).hashCode(), Doubles.hashCode(value));
81     }
82   }
83 
testIsFinite()84   public void testIsFinite() {
85     for (double value : NUMBERS) {
86       assertEquals(!(Double.isNaN(value) || Double.isInfinite(value)), Doubles.isFinite(value));
87     }
88   }
89 
testCompare()90   public void testCompare() {
91     for (double x : VALUES) {
92       for (double y : VALUES) {
93         // note: spec requires only that the sign is the same
94         assertEquals(x + ", " + y, Double.valueOf(x).compareTo(y), Doubles.compare(x, y));
95       }
96     }
97   }
98 
testContains()99   public void testContains() {
100     assertFalse(Doubles.contains(EMPTY, (double) 1));
101     assertFalse(Doubles.contains(ARRAY1, (double) 2));
102     assertFalse(Doubles.contains(ARRAY234, (double) 1));
103     assertTrue(Doubles.contains(new double[] {(double) -1}, (double) -1));
104     assertTrue(Doubles.contains(ARRAY234, (double) 2));
105     assertTrue(Doubles.contains(ARRAY234, (double) 3));
106     assertTrue(Doubles.contains(ARRAY234, (double) 4));
107 
108     for (double value : NUMBERS) {
109       assertTrue("" + value, Doubles.contains(new double[] {5.0, value}, value));
110     }
111     assertFalse(Doubles.contains(new double[] {5.0, NaN}, NaN));
112   }
113 
testIndexOf()114   public void testIndexOf() {
115     assertEquals(-1, Doubles.indexOf(EMPTY, (double) 1));
116     assertEquals(-1, Doubles.indexOf(ARRAY1, (double) 2));
117     assertEquals(-1, Doubles.indexOf(ARRAY234, (double) 1));
118     assertEquals(0, Doubles.indexOf(new double[] {(double) -1}, (double) -1));
119     assertEquals(0, Doubles.indexOf(ARRAY234, (double) 2));
120     assertEquals(1, Doubles.indexOf(ARRAY234, (double) 3));
121     assertEquals(2, Doubles.indexOf(ARRAY234, (double) 4));
122     assertEquals(
123         1,
124         Doubles.indexOf(new double[] {(double) 2, (double) 3, (double) 2, (double) 3}, (double) 3));
125 
126     for (double value : NUMBERS) {
127       assertEquals("" + value, 1, Doubles.indexOf(new double[] {5.0, value}, value));
128     }
129     assertEquals(-1, Doubles.indexOf(new double[] {5.0, NaN}, NaN));
130   }
131 
testIndexOf_arrayTarget()132   public void testIndexOf_arrayTarget() {
133     assertEquals(0, Doubles.indexOf(EMPTY, EMPTY));
134     assertEquals(0, Doubles.indexOf(ARRAY234, EMPTY));
135     assertEquals(-1, Doubles.indexOf(EMPTY, ARRAY234));
136     assertEquals(-1, Doubles.indexOf(ARRAY234, ARRAY1));
137     assertEquals(-1, Doubles.indexOf(ARRAY1, ARRAY234));
138     assertEquals(0, Doubles.indexOf(ARRAY1, ARRAY1));
139     assertEquals(0, Doubles.indexOf(ARRAY234, ARRAY234));
140     assertEquals(0, Doubles.indexOf(ARRAY234, new double[] {(double) 2, (double) 3}));
141     assertEquals(1, Doubles.indexOf(ARRAY234, new double[] {(double) 3, (double) 4}));
142     assertEquals(1, Doubles.indexOf(ARRAY234, new double[] {(double) 3}));
143     assertEquals(2, Doubles.indexOf(ARRAY234, new double[] {(double) 4}));
144     assertEquals(
145         1,
146         Doubles.indexOf(
147             new double[] {(double) 2, (double) 3, (double) 3, (double) 3, (double) 3},
148             new double[] {(double) 3}));
149     assertEquals(
150         2,
151         Doubles.indexOf(
152             new double[] {
153               (double) 2, (double) 3, (double) 2, (double) 3, (double) 4, (double) 2, (double) 3
154             },
155             new double[] {(double) 2, (double) 3, (double) 4}));
156     assertEquals(
157         1,
158         Doubles.indexOf(
159             new double[] {
160               (double) 2, (double) 2, (double) 3, (double) 4, (double) 2, (double) 3, (double) 4
161             },
162             new double[] {(double) 2, (double) 3, (double) 4}));
163     assertEquals(
164         -1,
165         Doubles.indexOf(
166             new double[] {(double) 4, (double) 3, (double) 2},
167             new double[] {(double) 2, (double) 3, (double) 4}));
168 
169     for (double value : NUMBERS) {
170       assertEquals(
171           "" + value,
172           1,
173           Doubles.indexOf(new double[] {5.0, value, value, 5.0}, new double[] {value, value}));
174     }
175     assertEquals(-1, Doubles.indexOf(new double[] {5.0, NaN, NaN, 5.0}, new double[] {NaN, NaN}));
176   }
177 
testLastIndexOf()178   public void testLastIndexOf() {
179     assertEquals(-1, Doubles.lastIndexOf(EMPTY, (double) 1));
180     assertEquals(-1, Doubles.lastIndexOf(ARRAY1, (double) 2));
181     assertEquals(-1, Doubles.lastIndexOf(ARRAY234, (double) 1));
182     assertEquals(0, Doubles.lastIndexOf(new double[] {(double) -1}, (double) -1));
183     assertEquals(0, Doubles.lastIndexOf(ARRAY234, (double) 2));
184     assertEquals(1, Doubles.lastIndexOf(ARRAY234, (double) 3));
185     assertEquals(2, Doubles.lastIndexOf(ARRAY234, (double) 4));
186     assertEquals(
187         3,
188         Doubles.lastIndexOf(
189             new double[] {(double) 2, (double) 3, (double) 2, (double) 3}, (double) 3));
190 
191     for (double value : NUMBERS) {
192       assertEquals("" + value, 0, Doubles.lastIndexOf(new double[] {value, 5.0}, value));
193     }
194     assertEquals(-1, Doubles.lastIndexOf(new double[] {NaN, 5.0}, NaN));
195   }
196 
197   @GwtIncompatible
testMax_noArgs()198   public void testMax_noArgs() {
199     try {
200       Doubles.max();
201       fail();
202     } catch (IllegalArgumentException expected) {
203     }
204   }
205 
testMax()206   public void testMax() {
207     assertEquals(LEAST, Doubles.max(LEAST));
208     assertEquals(GREATEST, Doubles.max(GREATEST));
209     assertEquals(
210         (double) 9,
211         Doubles.max(
212             (double) 8, (double) 6, (double) 7, (double) 5, (double) 3, (double) 0, (double) 9));
213 
214     assertEquals(0.0, Doubles.max(-0.0, 0.0));
215     assertEquals(0.0, Doubles.max(0.0, -0.0));
216     assertEquals(GREATEST, Doubles.max(NUMBERS));
217     assertTrue(Double.isNaN(Doubles.max(VALUES)));
218   }
219 
220   @GwtIncompatible
testMin_noArgs()221   public void testMin_noArgs() {
222     try {
223       Doubles.min();
224       fail();
225     } catch (IllegalArgumentException expected) {
226     }
227   }
228 
testMin()229   public void testMin() {
230     assertEquals(LEAST, Doubles.min(LEAST));
231     assertEquals(GREATEST, Doubles.min(GREATEST));
232     assertEquals(
233         (double) 0,
234         Doubles.min(
235             (double) 8, (double) 6, (double) 7, (double) 5, (double) 3, (double) 0, (double) 9));
236 
237     assertEquals(-0.0, Doubles.min(-0.0, 0.0));
238     assertEquals(-0.0, Doubles.min(0.0, -0.0));
239     assertEquals(LEAST, Doubles.min(NUMBERS));
240     assertTrue(Double.isNaN(Doubles.min(VALUES)));
241   }
242 
testConstrainToRange()243   public void testConstrainToRange() {
244     double tolerance = 1e-10;
245     assertEquals(
246         (double) 1, Doubles.constrainToRange((double) 1, (double) 0, (double) 5), tolerance);
247     assertEquals(
248         (double) 1, Doubles.constrainToRange((double) 1, (double) 1, (double) 5), tolerance);
249     assertEquals(
250         (double) 3, Doubles.constrainToRange((double) 1, (double) 3, (double) 5), tolerance);
251     assertEquals(
252         (double) -1, Doubles.constrainToRange((double) 0, (double) -5, (double) -1), tolerance);
253     assertEquals(
254         (double) 2, Doubles.constrainToRange((double) 5, (double) 2, (double) 2), tolerance);
255     try {
256       Doubles.constrainToRange((double) 1, (double) 3, (double) 2);
257       fail();
258     } catch (IllegalArgumentException expected) {
259     }
260   }
261 
testConcat()262   public void testConcat() {
263     assertTrue(Arrays.equals(EMPTY, Doubles.concat()));
264     assertTrue(Arrays.equals(EMPTY, Doubles.concat(EMPTY)));
265     assertTrue(Arrays.equals(EMPTY, Doubles.concat(EMPTY, EMPTY, EMPTY)));
266     assertTrue(Arrays.equals(ARRAY1, Doubles.concat(ARRAY1)));
267     assertNotSame(ARRAY1, Doubles.concat(ARRAY1));
268     assertTrue(Arrays.equals(ARRAY1, Doubles.concat(EMPTY, ARRAY1, EMPTY)));
269     assertTrue(
270         Arrays.equals(
271             new double[] {(double) 1, (double) 1, (double) 1},
272             Doubles.concat(ARRAY1, ARRAY1, ARRAY1)));
273     assertTrue(
274         Arrays.equals(
275             new double[] {(double) 1, (double) 2, (double) 3, (double) 4},
276             Doubles.concat(ARRAY1, ARRAY234)));
277   }
278 
testEnsureCapacity()279   public void testEnsureCapacity() {
280     assertSame(EMPTY, Doubles.ensureCapacity(EMPTY, 0, 1));
281     assertSame(ARRAY1, Doubles.ensureCapacity(ARRAY1, 0, 1));
282     assertSame(ARRAY1, Doubles.ensureCapacity(ARRAY1, 1, 1));
283     assertTrue(
284         Arrays.equals(
285             new double[] {(double) 1, (double) 0, (double) 0},
286             Doubles.ensureCapacity(ARRAY1, 2, 1)));
287   }
288 
testEnsureCapacity_fail()289   public void testEnsureCapacity_fail() {
290     try {
291       Doubles.ensureCapacity(ARRAY1, -1, 1);
292       fail();
293     } catch (IllegalArgumentException expected) {
294     }
295     try {
296       // notice that this should even fail when no growth was needed
297       Doubles.ensureCapacity(ARRAY1, 1, -1);
298       fail();
299     } catch (IllegalArgumentException expected) {
300     }
301   }
302 
303   @GwtIncompatible // Double.toString returns different value in GWT.
testJoin()304   public void testJoin() {
305     assertEquals("", Doubles.join(",", EMPTY));
306     assertEquals("1.0", Doubles.join(",", ARRAY1));
307     assertEquals("1.0,2.0", Doubles.join(",", (double) 1, (double) 2));
308     assertEquals("1.02.03.0", Doubles.join("", (double) 1, (double) 2, (double) 3));
309   }
310 
testJoinNonTrivialDoubles()311   public void testJoinNonTrivialDoubles() {
312     assertEquals("", Doubles.join(",", EMPTY));
313     assertEquals("1.2", Doubles.join(",", 1.2));
314     assertEquals("1.3,2.4", Doubles.join(",", 1.3, 2.4));
315     assertEquals("1.42.53.6", Doubles.join("", 1.4, 2.5, 3.6));
316   }
317 
testLexicographicalComparator()318   public void testLexicographicalComparator() {
319     List<double[]> ordered =
320         Arrays.asList(
321             new double[] {},
322             new double[] {LEAST},
323             new double[] {LEAST, LEAST},
324             new double[] {LEAST, (double) 1},
325             new double[] {(double) 1},
326             new double[] {(double) 1, LEAST},
327             new double[] {GREATEST, Double.MAX_VALUE},
328             new double[] {GREATEST, GREATEST},
329             new double[] {GREATEST, GREATEST, GREATEST});
330 
331     Comparator<double[]> comparator = Doubles.lexicographicalComparator();
332     Helpers.testComparator(comparator, ordered);
333   }
334 
testReverse()335   public void testReverse() {
336     testReverse(new double[] {}, new double[] {});
337     testReverse(new double[] {1}, new double[] {1});
338     testReverse(new double[] {1, 2}, new double[] {2, 1});
339     testReverse(new double[] {3, 1, 1}, new double[] {1, 1, 3});
340     testReverse(new double[] {-1, 1, -2, 2}, new double[] {2, -2, 1, -1});
341   }
342 
testReverse(double[] input, double[] expectedOutput)343   private static void testReverse(double[] input, double[] expectedOutput) {
344     input = Arrays.copyOf(input, input.length);
345     Doubles.reverse(input);
346     assertTrue(Arrays.equals(expectedOutput, input));
347   }
348 
testReverse( double[] input, int fromIndex, int toIndex, double[] expectedOutput)349   private static void testReverse(
350       double[] input, int fromIndex, int toIndex, double[] expectedOutput) {
351     input = Arrays.copyOf(input, input.length);
352     Doubles.reverse(input, fromIndex, toIndex);
353     assertTrue(Arrays.equals(expectedOutput, input));
354   }
355 
testReverseIndexed()356   public void testReverseIndexed() {
357     testReverse(new double[] {}, 0, 0, new double[] {});
358     testReverse(new double[] {1}, 0, 1, new double[] {1});
359     testReverse(new double[] {1, 2}, 0, 2, new double[] {2, 1});
360     testReverse(new double[] {3, 1, 1}, 0, 2, new double[] {1, 3, 1});
361     testReverse(new double[] {3, 1, 1}, 0, 1, new double[] {3, 1, 1});
362     testReverse(new double[] {-1, 1, -2, 2}, 1, 3, new double[] {-1, -2, 1, 2});
363   }
364 
testSortDescending()365   public void testSortDescending() {
366     testSortDescending(new double[] {}, new double[] {});
367     testSortDescending(new double[] {1}, new double[] {1});
368     testSortDescending(new double[] {1, 2}, new double[] {2, 1});
369     testSortDescending(new double[] {1, 3, 1}, new double[] {3, 1, 1});
370     testSortDescending(new double[] {-1, 1, -2, 2}, new double[] {2, 1, -1, -2});
371     testSortDescending(
372         new double[] {-1, 1, Double.NaN, -2, -0, 0, 2},
373         new double[] {Double.NaN, 2, 1, 0, -0, -1, -2});
374   }
375 
testSortDescending(double[] input, double[] expectedOutput)376   private static void testSortDescending(double[] input, double[] expectedOutput) {
377     input = Arrays.copyOf(input, input.length);
378     Doubles.sortDescending(input);
379     // GWT's Arrays.equals doesn't appear to handle NaN correctly, so test each element individually
380     for (int i = 0; i < input.length; i++) {
381       assertEquals(0, Double.compare(expectedOutput[i], input[i]));
382     }
383   }
384 
testSortDescending( double[] input, int fromIndex, int toIndex, double[] expectedOutput)385   private static void testSortDescending(
386       double[] input, int fromIndex, int toIndex, double[] expectedOutput) {
387     input = Arrays.copyOf(input, input.length);
388     Doubles.sortDescending(input, fromIndex, toIndex);
389     // GWT's Arrays.equals doesn't appear to handle NaN correctly, so test each element individually
390     for (int i = 0; i < input.length; i++) {
391       assertEquals(0, Double.compare(expectedOutput[i], input[i]));
392     }
393   }
394 
testSortDescendingIndexed()395   public void testSortDescendingIndexed() {
396     testSortDescending(new double[] {}, 0, 0, new double[] {});
397     testSortDescending(new double[] {1}, 0, 1, new double[] {1});
398     testSortDescending(new double[] {1, 2}, 0, 2, new double[] {2, 1});
399     testSortDescending(new double[] {1, 3, 1}, 0, 2, new double[] {3, 1, 1});
400     testSortDescending(new double[] {1, 3, 1}, 0, 1, new double[] {1, 3, 1});
401     testSortDescending(new double[] {-1, -2, 1, 2}, 1, 3, new double[] {-1, 1, -2, 2});
402     testSortDescending(
403         new double[] {-1, 1, Double.NaN, -2, 2}, 1, 4, new double[] {-1, Double.NaN, 1, -2, 2});
404   }
405 
406   @GwtIncompatible // SerializableTester
testLexicographicalComparatorSerializable()407   public void testLexicographicalComparatorSerializable() {
408     Comparator<double[]> comparator = Doubles.lexicographicalComparator();
409     assertSame(comparator, SerializableTester.reserialize(comparator));
410   }
411 
412   @GwtIncompatible // SerializableTester
testStringConverterSerialization()413   public void testStringConverterSerialization() {
414     SerializableTester.reserializeAndAssert(Doubles.stringConverter());
415   }
416 
testToArray()417   public void testToArray() {
418     // need explicit type parameter to avoid javac warning!?
419     List<Double> none = Arrays.<Double>asList();
420     assertTrue(Arrays.equals(EMPTY, Doubles.toArray(none)));
421 
422     List<Double> one = Arrays.asList((double) 1);
423     assertTrue(Arrays.equals(ARRAY1, Doubles.toArray(one)));
424 
425     double[] array = {(double) 0, (double) 1, Math.PI};
426 
427     List<Double> three = Arrays.asList((double) 0, (double) 1, Math.PI);
428     assertTrue(Arrays.equals(array, Doubles.toArray(three)));
429 
430     assertTrue(Arrays.equals(array, Doubles.toArray(Doubles.asList(array))));
431   }
432 
testToArray_threadSafe()433   public void testToArray_threadSafe() {
434     for (int delta : new int[] {+1, 0, -1}) {
435       for (int i = 0; i < VALUES.length; i++) {
436         List<Double> list = Doubles.asList(VALUES).subList(0, i);
437         Collection<Double> misleadingSize = Helpers.misleadingSizeCollection(delta);
438         misleadingSize.addAll(list);
439         double[] arr = Doubles.toArray(misleadingSize);
440         assertEquals(i, arr.length);
441         for (int j = 0; j < i; j++) {
442           assertEquals(VALUES[j], arr[j]);
443         }
444       }
445     }
446   }
447 
testToArray_withNull()448   public void testToArray_withNull() {
449     List<Double> list = Arrays.asList((double) 0, (double) 1, null);
450     try {
451       Doubles.toArray(list);
452       fail();
453     } catch (NullPointerException expected) {
454     }
455   }
456 
testToArray_withConversion()457   public void testToArray_withConversion() {
458     double[] array = {(double) 0, (double) 1, (double) 2};
459 
460     List<Byte> bytes = Arrays.asList((byte) 0, (byte) 1, (byte) 2);
461     List<Short> shorts = Arrays.asList((short) 0, (short) 1, (short) 2);
462     List<Integer> ints = Arrays.asList(0, 1, 2);
463     List<Float> floats = Arrays.asList((float) 0, (float) 1, (float) 2);
464     List<Long> longs = Arrays.asList((long) 0, (long) 1, (long) 2);
465     List<Double> doubles = Arrays.asList((double) 0, (double) 1, (double) 2);
466 
467     assertTrue(Arrays.equals(array, Doubles.toArray(bytes)));
468     assertTrue(Arrays.equals(array, Doubles.toArray(shorts)));
469     assertTrue(Arrays.equals(array, Doubles.toArray(ints)));
470     assertTrue(Arrays.equals(array, Doubles.toArray(floats)));
471     assertTrue(Arrays.equals(array, Doubles.toArray(longs)));
472     assertTrue(Arrays.equals(array, Doubles.toArray(doubles)));
473   }
474 
testAsList_isAView()475   public void testAsList_isAView() {
476     double[] array = {(double) 0, (double) 1};
477     List<Double> list = Doubles.asList(array);
478     list.set(0, (double) 2);
479     assertTrue(Arrays.equals(new double[] {(double) 2, (double) 1}, array));
480     array[1] = (double) 3;
481     assertThat(list).containsExactly((double) 2, (double) 3).inOrder();
482   }
483 
testAsList_toArray_roundTrip()484   public void testAsList_toArray_roundTrip() {
485     double[] array = {(double) 0, (double) 1, (double) 2};
486     List<Double> list = Doubles.asList(array);
487     double[] newArray = Doubles.toArray(list);
488 
489     // Make sure it returned a copy
490     list.set(0, (double) 4);
491     assertTrue(Arrays.equals(new double[] {(double) 0, (double) 1, (double) 2}, newArray));
492     newArray[1] = (double) 5;
493     assertEquals((double) 1, (double) list.get(1));
494   }
495 
496   // This test stems from a real bug found by andrewk
testAsList_subList_toArray_roundTrip()497   public void testAsList_subList_toArray_roundTrip() {
498     double[] array = {(double) 0, (double) 1, (double) 2, (double) 3};
499     List<Double> list = Doubles.asList(array);
500     assertTrue(
501         Arrays.equals(new double[] {(double) 1, (double) 2}, Doubles.toArray(list.subList(1, 3))));
502     assertTrue(Arrays.equals(new double[] {}, Doubles.toArray(list.subList(2, 2))));
503   }
504 
testAsListEmpty()505   public void testAsListEmpty() {
506     assertSame(Collections.emptyList(), Doubles.asList(EMPTY));
507   }
508 
509   /**
510    * A reference implementation for {@code tryParse} that just catches the exception from {@link
511    * Double#valueOf}.
512    */
referenceTryParse(String input)513   private static Double referenceTryParse(String input) {
514     if (input.trim().length() < input.length()) {
515       return null;
516     }
517     try {
518       return Double.valueOf(input);
519     } catch (NumberFormatException e) {
520       return null;
521     }
522   }
523 
524   @GwtIncompatible // Doubles.tryParse
checkTryParse(String input)525   private static void checkTryParse(String input) {
526     Double expected = referenceTryParse(input);
527     assertEquals(expected, Doubles.tryParse(input));
528     if (expected != null && !Doubles.FLOATING_POINT_PATTERN.matcher(input).matches()) {
529       // TODO(cpovirk): Use SourceCodeEscapers if it is added to Guava.
530       StringBuilder escapedInput = new StringBuilder();
531       for (char c : input.toCharArray()) {
532         if (c >= 0x20 && c <= 0x7E) {
533           escapedInput.append(c);
534         } else {
535           escapedInput.append(String.format("\\u%04x", (int) c));
536         }
537       }
538       fail("FLOATING_POINT_PATTERN should have matched valid input <" + escapedInput + ">");
539     }
540   }
541 
542   @GwtIncompatible // Doubles.tryParse
checkTryParse(double expected, String input)543   private static void checkTryParse(double expected, String input) {
544     assertEquals(Double.valueOf(expected), Doubles.tryParse(input));
545     assertThat(input)
546         .matches(
547             Pattern.compile(
548                 Doubles.FLOATING_POINT_PATTERN.pattern(), Doubles.FLOATING_POINT_PATTERN.flags()));
549   }
550 
551   @GwtIncompatible // Doubles.tryParse
testTryParseHex()552   public void testTryParseHex() {
553     for (String signChar : ImmutableList.of("", "+", "-")) {
554       for (String hexPrefix : ImmutableList.of("0x", "0X")) {
555         for (String iPart : ImmutableList.of("", "0", "1", "F", "f", "c4", "CE")) {
556           for (String fPart : ImmutableList.of("", ".", ".F", ".52", ".a")) {
557             for (String expMarker : ImmutableList.of("p", "P")) {
558               for (String exponent : ImmutableList.of("0", "-5", "+20", "52")) {
559                 for (String typePart : ImmutableList.of("", "D", "F", "d", "f")) {
560                   checkTryParse(
561                       signChar + hexPrefix + iPart + fPart + expMarker + exponent + typePart);
562                 }
563               }
564             }
565           }
566         }
567       }
568     }
569   }
570 
571   @AndroidIncompatible // slow
572   @GwtIncompatible // Doubles.tryParse
testTryParseAllCodePoints()573   public void testTryParseAllCodePoints() {
574     // Exercise non-ASCII digit test cases and the like.
575     char[] tmp = new char[2];
576     for (int i = Character.MIN_CODE_POINT; i < Character.MAX_CODE_POINT; i++) {
577       Character.toChars(i, tmp, 0);
578       checkTryParse(String.copyValueOf(tmp, 0, Character.charCount(i)));
579     }
580   }
581 
582   @GwtIncompatible // Doubles.tryParse
testTryParseOfToStringIsOriginal()583   public void testTryParseOfToStringIsOriginal() {
584     for (double d : NUMBERS) {
585       checkTryParse(d, Double.toString(d));
586     }
587   }
588 
589   @GwtIncompatible // Doubles.tryParse
testTryParseOfToHexStringIsOriginal()590   public void testTryParseOfToHexStringIsOriginal() {
591     for (double d : NUMBERS) {
592       checkTryParse(d, Double.toHexString(d));
593     }
594   }
595 
596   @GwtIncompatible // Doubles.tryParse
testTryParseNaN()597   public void testTryParseNaN() {
598     checkTryParse("NaN");
599     checkTryParse("+NaN");
600     checkTryParse("-NaN");
601   }
602 
603   @GwtIncompatible // Doubles.tryParse
testTryParseInfinity()604   public void testTryParseInfinity() {
605     checkTryParse(Double.POSITIVE_INFINITY, "Infinity");
606     checkTryParse(Double.POSITIVE_INFINITY, "+Infinity");
607     checkTryParse(Double.NEGATIVE_INFINITY, "-Infinity");
608   }
609 
610   private static final String[] BAD_TRY_PARSE_INPUTS = {
611     "",
612     "+-",
613     "+-0",
614     " 5",
615     "32 ",
616     " 55 ",
617     "infinity",
618     "POSITIVE_INFINITY",
619     "0x9A",
620     "0x9A.bE-5",
621     ".",
622     ".e5",
623     "NaNd",
624     "InfinityF"
625   };
626 
627   @GwtIncompatible // Doubles.tryParse
testTryParseFailures()628   public void testTryParseFailures() {
629     for (String badInput : BAD_TRY_PARSE_INPUTS) {
630       assertThat(badInput)
631           .doesNotMatch(
632               Pattern.compile(
633                   Doubles.FLOATING_POINT_PATTERN.pattern(),
634                   Doubles.FLOATING_POINT_PATTERN.flags()));
635       assertEquals(referenceTryParse(badInput), Doubles.tryParse(badInput));
636       assertNull(Doubles.tryParse(badInput));
637     }
638   }
639 
640   @GwtIncompatible // NullPointerTester
testNulls()641   public void testNulls() {
642     new NullPointerTester().testAllPublicStaticMethods(Doubles.class);
643   }
644 
testStringConverter_convert()645   public void testStringConverter_convert() {
646     Converter<String, Double> converter = Doubles.stringConverter();
647     assertEquals((Double) 1.0, converter.convert("1.0"));
648     assertEquals((Double) 0.0, converter.convert("0.0"));
649     assertEquals((Double) (-1.0), converter.convert("-1.0"));
650     assertEquals((Double) 1.0, converter.convert("1"));
651     assertEquals((Double) 0.0, converter.convert("0"));
652     assertEquals((Double) (-1.0), converter.convert("-1"));
653     assertEquals((Double) 1e6, converter.convert("1e6"));
654     assertEquals((Double) 1e-6, converter.convert("1e-6"));
655   }
656 
testStringConverter_convertError()657   public void testStringConverter_convertError() {
658     try {
659       Doubles.stringConverter().convert("notanumber");
660       fail();
661     } catch (NumberFormatException expected) {
662     }
663   }
664 
testStringConverter_nullConversions()665   public void testStringConverter_nullConversions() {
666     assertNull(Doubles.stringConverter().convert(null));
667     assertNull(Doubles.stringConverter().reverse().convert(null));
668   }
669 
670   @GwtIncompatible // Double.toString returns different value in GWT.
testStringConverter_reverse()671   public void testStringConverter_reverse() {
672     Converter<String, Double> converter = Doubles.stringConverter();
673     assertEquals("1.0", converter.reverse().convert(1.0));
674     assertEquals("0.0", converter.reverse().convert(0.0));
675     assertEquals("-1.0", converter.reverse().convert(-1.0));
676     assertEquals("1000000.0", converter.reverse().convert(1e6));
677     assertEquals("1.0E-6", converter.reverse().convert(1e-6));
678   }
679 
680   @GwtIncompatible // NullPointerTester
testStringConverter_nullPointerTester()681   public void testStringConverter_nullPointerTester() throws Exception {
682     NullPointerTester tester = new NullPointerTester();
683     tester.testAllPublicInstanceMethods(Doubles.stringConverter());
684   }
685 
686   @GwtIncompatible
testTryParse_withNullNoGwt()687   public void testTryParse_withNullNoGwt() {
688     assertNull(Doubles.tryParse("null"));
689     try {
690       Doubles.tryParse(null);
691       fail("Expected NPE");
692     } catch (NullPointerException expected) {
693     }
694   }
695 }
696