1 /*
   2  * Copyright 2001-2003 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 4160406 4705734 4707389 4826774 4895911
  27  * @summary Test for Double.parseDouble method and acceptance regex
  28  */
  29 
  30 import java.util.regex.*;
  31 
  32 public class ParseDouble {
  33 
  34     private static void check(String val, double expected) {
  35         double n = Double.parseDouble(val);
  36         if (n != expected)
  37             throw new RuntimeException("Double.parseDouble failed. String:" +
  38                                                 val + " Result:" + n);
  39     }
  40 
  41     private static void rudimentaryTest() {
  42         check(new String(""+Double.MIN_VALUE), Double.MIN_VALUE);
  43         check(new String(""+Double.MAX_VALUE), Double.MAX_VALUE);
  44 
  45         check("10",     (double)  10.0);
  46         check("10.0",   (double)  10.0);
  47         check("10.01",  (double)  10.01);
  48 
  49         check("-10",    (double) -10.0);
  50         check("-10.00", (double) -10.0);
  51         check("-10.01", (double) -10.01);
  52     }
  53 
  54 
  55     static  String badStrings[] = {
  56         "",
  57         "+",
  58         "-",
  59         "+e",
  60         "-e",
  61         "+e170",
  62         "-e170",
  63 
  64         // Make sure intermediate white space is not deleted.
  65         "1234   e10",
  66         "-1234   e10",
  67 
  68         // Control characters in the interior of a string are not legal
  69         "1\u0007e1",
  70         "1e\u00071",
  71 
  72         // NaN and infinity can't have trailing type suffices or exponents
  73         "NaNf",
  74         "NaNF",
  75         "NaNd",
  76         "NaND",
  77         "-NaNf",
  78         "-NaNF",
  79         "-NaNd",
  80         "-NaND",
  81         "+NaNf",
  82         "+NaNF",
  83         "+NaNd",
  84         "+NaND",
  85         "Infinityf",
  86         "InfinityF",
  87         "Infinityd",
  88         "InfinityD",
  89         "-Infinityf",
  90         "-InfinityF",
  91         "-Infinityd",
  92         "-InfinityD",
  93         "+Infinityf",
  94         "+InfinityF",
  95         "+Infinityd",
  96         "+InfinityD",
  97 
  98         "NaNe10",
  99         "-NaNe10",
 100         "+NaNe10",
 101         "Infinitye10",
 102         "-Infinitye10",
 103         "+Infinitye10",
 104 
 105         // Non-ASCII digits are not recognized
 106         "\u0661e\u0661", // 1e1 in Arabic-Indic digits
 107         "\u06F1e\u06F1", // 1e1 in Extended Arabic-Indic digits
 108         "\u0967e\u0967", // 1e1 in Devanagari digits
 109 
 110         // JCK test lex03592m3
 111         ".",
 112 
 113         // JCK test lex03592m4
 114         "e42",
 115 
 116         // JCK test lex03592m5
 117         ".e42",
 118 
 119         // JCK test lex03592m6
 120         "d",
 121 
 122         // JCK test lex03592m7
 123         ".d",
 124 
 125         // JCK test lex03592m8
 126         "e42d",
 127 
 128         // JCK test lex03592m9
 129         ".e42d",
 130 
 131         // JCK test lex03593m10
 132         "1A01.01125e-10d",
 133 
 134         // JCK test lex03593m11
 135         "2;3.01125e-10d",
 136 
 137         // JCK test lex03593m12
 138         "1_34.01125e-10d",
 139 
 140         // JCK test lex03593m14
 141         "202..01125e-10d",
 142 
 143         // JCK test lex03593m15
 144         "202,01125e-10d",
 145 
 146         // JCK test lex03593m16
 147         "202.03b4e-10d",
 148 
 149         // JCK test lex03593m18
 150         "202.06_3e-10d",
 151 
 152         // JCK test lex03593m20
 153         "202.01125e-f0d",
 154 
 155         // JCK test lex03593m21
 156         "202.01125e_3d",
 157 
 158         // JCK test lex03593m22
 159         "202.01125e -5d",
 160 
 161         // JCK test lex03593m24
 162         "202.01125e-10r",
 163 
 164         // JCK test lex03593m25
 165         "202.01125e-10ff",
 166 
 167         // JCK test lex03593m26
 168         "1234L.01",
 169 
 170         // JCK test lex03593m27
 171         "12ee-2",
 172 
 173         // JCK test lex03593m28
 174         "12e-2.2.2",
 175 
 176         // JCK test lex03593m29
 177         "12.01e+",
 178 
 179         // JCK test lex03593m30
 180         "12.01E",
 181 
 182         // Bad hexadecimal-style strings
 183 
 184         // Two leading zeros
 185         "00x1.0p1",
 186 
 187         // Must have hex specifier
 188         "1.0p1",
 189         "00010p1",
 190         "deadbeefp1",
 191 
 192         // Need an explicit fully-formed exponent
 193         "0x1.0p",
 194         "0x1.0",
 195 
 196         // Exponent must be in decimal
 197         "0x1.0pa",
 198         "0x1.0pf",
 199 
 200         // Exponent separated by "p"
 201         "0x1.0e22",
 202         "0x1.0e22",
 203 
 204         // Need a signifcand
 205         "0xp22"
 206     };
 207 
 208     static String goodStrings[] = {
 209         "NaN",
 210         "+NaN",
 211         "-NaN",
 212         "Infinity",
 213         "+Infinity",
 214         "-Infinity",
 215         "1.1e-23f",
 216         ".1e-23f",
 217         "1e-23",
 218         "1f",
 219         "0",
 220         "-0",
 221         "+0",
 222         "00",
 223         "00",
 224         "-00",
 225         "+00",
 226         "0000000000",
 227         "-0000000000",
 228         "+0000000000",
 229         "1",
 230         "2",
 231         "1234",
 232         "-1234",
 233         "+1234",
 234         "2147483647",   // Integer.MAX_VALUE
 235         "2147483648",
 236         "-2147483648",  // Integer.MIN_VALUE
 237         "-2147483649",
 238 
 239         "16777215",
 240         "16777216",     // 2^24
 241         "16777217",
 242 
 243         "-16777215",
 244         "-16777216",    // -2^24
 245         "-16777217",
 246 
 247         "9007199254740991",
 248         "9007199254740992",     // 2^53
 249         "9007199254740993",
 250 
 251         "-9007199254740991",
 252         "-9007199254740992",    // -2^53
 253         "-9007199254740993",
 254 
 255         "9223372036854775807",
 256         "9223372036854775808",  // Long.MAX_VALUE
 257         "9223372036854775809",
 258 
 259         "-9223372036854775808",
 260         "-9223372036854775809", // Long.MIN_VALUE
 261         "-9223372036854775810",
 262 
 263         // Culled from JCK test lex03591m1
 264         "54.07140d",
 265         "7.01e-324d",
 266         "2147483647.01d",
 267         "1.2147483647f",
 268         "000000000000000000000000001.F",
 269         "1.00000000000000000000000000e-2F",
 270 
 271         // Culled from JCK test lex03592m2
 272         "2.",
 273         ".0909",
 274         "122112217090.0",
 275         "7090e-5",
 276         "2.E-20",
 277         ".0909e42",
 278         "122112217090.0E+100",
 279         "7090f",
 280         "2.F",
 281         ".0909d",
 282         "122112217090.0D",
 283         "7090e-5f",
 284         "2.E-20F",
 285         ".0909e42d",
 286         "122112217090.0E+100D",
 287 
 288         // Culled from JCK test lex03594m31 -- unicode escapes
 289         "\u0035\u0031\u0034\u0039\u0032\u0033\u0036\u0037\u0038\u0030.1102E-209D",
 290         "1290873\u002E12301e100",
 291         "1.1E-10\u0066",
 292 
 293         // Culled from JCK test lex03595m1
 294         "0.0E-10",
 295         "1E10",
 296 
 297         // Culled from JCK test lex03691m1
 298         "0.f",
 299         "1f",
 300         "0.F",
 301         "1F",
 302         "0.12d",
 303         "1e-0d",
 304         "12.e+1D",
 305         "0e-0D",
 306         "12.e+01",
 307         "1e-01",
 308 
 309         // Good hex strings
 310         // Vary capitalization of separators.
 311 
 312         "0x1p1",
 313         "0X1p1",
 314         "0x1P1",
 315         "0X1P1",
 316         "0x1p1f",
 317         "0X1p1f",
 318         "0x1P1f",
 319         "0X1P1f",
 320         "0x1p1F",
 321         "0X1p1F",
 322         "0x1P1F",
 323         "0X1P1F",
 324         "0x1p1d",
 325         "0X1p1d",
 326         "0x1P1d",
 327         "0X1P1d",
 328         "0x1p1D",
 329         "0X1p1D",
 330         "0x1P1D",
 331         "0X1P1D",
 332 
 333         "-0x1p1",
 334         "-0X1p1",
 335         "-0x1P1",
 336         "-0X1P1",
 337         "-0x1p1f",
 338         "-0X1p1f",
 339         "-0x1P1f",
 340         "-0X1P1f",
 341         "-0x1p1F",
 342         "-0X1p1F",
 343         "-0x1P1F",
 344         "-0X1P1F",
 345         "-0x1p1d",
 346         "-0X1p1d",
 347         "-0x1P1d",
 348         "-0X1P1d",
 349         "-0x1p1D",
 350         "-0X1p1D",
 351         "-0x1P1D",
 352         "-0X1P1D",
 353 
 354         "0x1p-1",
 355         "0X1p-1",
 356         "0x1P-1",
 357         "0X1P-1",
 358         "0x1p-1f",
 359         "0X1p-1f",
 360         "0x1P-1f",
 361         "0X1P-1f",
 362         "0x1p-1F",
 363         "0X1p-1F",
 364         "0x1P-1F",
 365         "0X1P-1F",
 366         "0x1p-1d",
 367         "0X1p-1d",
 368         "0x1P-1d",
 369         "0X1P-1d",
 370         "0x1p-1D",
 371         "0X1p-1D",
 372         "0x1P-1D",
 373         "0X1P-1D",
 374 
 375         "-0x1p-1",
 376         "-0X1p-1",
 377         "-0x1P-1",
 378         "-0X1P-1",
 379         "-0x1p-1f",
 380         "-0X1p-1f",
 381         "-0x1P-1f",
 382         "-0X1P-1f",
 383         "-0x1p-1F",
 384         "-0X1p-1F",
 385         "-0x1P-1F",
 386         "-0X1P-1F",
 387         "-0x1p-1d",
 388         "-0X1p-1d",
 389         "-0x1P-1d",
 390         "-0X1P-1d",
 391         "-0x1p-1D",
 392         "-0X1p-1D",
 393         "-0x1P-1D",
 394         "-0X1P-1D",
 395 
 396 
 397         // Try different significand combinations
 398         "0xap1",
 399         "0xbp1",
 400         "0xcp1",
 401         "0xdp1",
 402         "0xep1",
 403         "0xfp1",
 404 
 405         "0x1p1",
 406         "0x.1p1",
 407         "0x1.1p1",
 408 
 409         "0x001p23",
 410         "0x00.1p1",
 411         "0x001.1p1",
 412 
 413         "0x100p1",
 414         "0x.100p1",
 415         "0x1.100p1",
 416 
 417         "0x00100p1",
 418         "0x00.100p1",
 419         "0x001.100p1"
 420     };
 421 
 422     static String paddedBadStrings[];
 423     static String paddedGoodStrings[];
 424     static {
 425         String pad = " \t\n\r\f\u0001\u000b\u001f";
 426         paddedBadStrings = new String[badStrings.length];
 427         for(int i = 0 ; i <  badStrings.length; i++)
 428             paddedBadStrings[i] = pad + badStrings[i] + pad;
 429 
 430         paddedGoodStrings = new String[goodStrings.length];
 431         for(int i = 0 ; i <  goodStrings.length; i++)
 432             paddedGoodStrings[i] = pad + goodStrings[i] + pad;
 433 
 434     }
 435 
 436 
 437     /*
 438      * Throws an exception if <code>Input</code> is
 439      * <code>exceptionalInput</code> and {@link Double.parseDouble
 440      * parseDouble} does <em>not</em> throw an exception or if
 441      * <code>Input</code> is not <code>exceptionalInput</code> and
 442      * <code>parseDouble</code> throws an exception.  This method does
 443      * not attempt to test whether the string is converted to the
 444      * proper value; just whether the input is accepted appropriately
 445      * or not.
 446      */
 447     private static void testParsing(String [] input,
 448                                     boolean exceptionalInput) {
 449         for(int i = 0; i < input.length; i++) {
 450             double d;
 451 
 452             try {
 453                 d = Double.parseDouble(input[i]);
 454             }
 455             catch (NumberFormatException e) {
 456                 if (! exceptionalInput) {
 457                     throw new RuntimeException("Double.parseDouble rejected " +
 458                                                "good string `" + input[i] +
 459                                                "'.");
 460                 }
 461                 break;
 462             }
 463             if (exceptionalInput) {
 464                 throw new RuntimeException("Double.parseDouble accepted " +
 465                                            "bad string `" + input[i] +
 466                                            "'.");
 467             }
 468         }
 469     }
 470 
 471     /*
 472      * Throws an exception if <code>Input</code> is
 473      * <code>exceptionalInput</code> and the regular expression
 474      * matches one of the strings or if <code>Input</code> is not
 475      * <code>exceptionalInput</code> and the regular expression fails
 476      * to match an input string.
 477      */
 478     private static void testRegex(String [] input, boolean exceptionalInput) {
 479         /*
 480          * The regex below is taken from the JavaDoc for
 481          * Double.valueOf.
 482          */
 483 
 484         final String Digits     = "(\\p{Digit}+)";
 485         final String HexDigits  = "(\\p{XDigit}+)";
 486         // an exponent is 'e' or 'E' followed by an optionally
 487         // signed decimal integer.
 488         final String Exp        = "[eE][+-]?"+Digits;
 489         final String fpRegex    =
 490             ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
 491              "[+-]?(" + // Optional sign character
 492              "NaN|" +           // "NaN" string
 493              "Infinity|" +      // "Infinity" string
 494 
 495              // A floating-point string representing a finite positive
 496              // number without a leading sign has at most five basic pieces:
 497              // Digits . Digits ExponentPart FloatTypeSuffix
 498              //
 499              // Since this method allows integer-only strings as input
 500              // in addition to strings of floating-point literals, the
 501              // two sub-patterns below are simplifications of the grammar
 502              // productions from the Java Language Specification, 2nd
 503              // edition, section 3.10.2.
 504 
 505 
 506              // A decimal floating-point string representing a finite positive
 507              // number without a leading sign has at most five basic pieces:
 508              // Digits . Digits ExponentPart FloatTypeSuffix
 509              //
 510              // Since this method allows integer-only strings as input
 511              // in addition to strings of floating-point literals, the
 512              // two sub-patterns below are simplifications of the grammar
 513              // productions from the Java Language Specification, 2nd
 514              // edition, section 3.10.2.
 515 
 516              // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
 517              "(((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
 518 
 519              // . Digits ExponentPart_opt FloatTypeSuffix_opt
 520              "(\\.("+Digits+")("+Exp+")?))|"+
 521 
 522             // Hexadecimal strings
 523             "((" +
 524              // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
 525              "(0[xX]" + HexDigits + "(\\.)?)|" +
 526 
 527              // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
 528              "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
 529 
 530              ")[pP][+-]?" + Digits + "))" +
 531              "[fFdD]?))" +
 532              "[\\x00-\\x20]*");// Optional trailing "whitespace"
 533         Pattern fpPattern = Pattern.compile(fpRegex);
 534 
 535         for(int i = 0; i < input.length; i++) {
 536              Matcher m = fpPattern.matcher(input[i]);
 537              if (m.matches() != ! exceptionalInput) {
 538                  throw new RuntimeException("Regular expression " +
 539                                             (exceptionalInput?
 540                                              "accepted bad":
 541                                              "rejected good") +
 542                                             " string `" +
 543                                             input[i] + "'.");
 544              }
 545         }
 546 
 547     }
 548 
 549     public static void main(String[] args) throws Exception {
 550         rudimentaryTest();
 551 
 552         testParsing(goodStrings, false);
 553         testParsing(paddedGoodStrings, false);
 554         testParsing(badStrings, true);
 555         testParsing(paddedBadStrings, true);
 556 
 557         testRegex(goodStrings, false);
 558         testRegex(paddedGoodStrings, false);
 559         testRegex(badStrings, true);
 560         testRegex(paddedBadStrings, true);
 561     }
 562 }