1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @summary Unit test for jdk.Version.
  27  * @bug 8072379
  28  */
  29 
  30 import java.lang.reflect.InvocationTargetException;
  31 import java.lang.reflect.Method;
  32 import java.math.BigInteger;
  33 import java.util.stream.Collectors;
  34 import java.util.Arrays;
  35 import java.util.ArrayList;
  36 import java.util.List;
  37 import java.util.Optional;
  38 
  39 import jdk.Version;
  40 import static java.lang.System.out;
  41 
  42 public class Basic {
  43     private static final Class<? extends Throwable> IAE 
  44         = IllegalArgumentException.class;
  45     private static final Class<? extends Throwable> NPE 
  46         = NullPointerException.class;
  47     private static final Class<? extends Throwable> NFE
  48         = NumberFormatException.class;
  49     private static final Class<?> VERSION = Version.class;
  50 
  51     private static final BigInteger TOO_BIG
  52         = (BigInteger.valueOf(Integer.MAX_VALUE)).add(BigInteger.ONE);
  53     private static final String TOO_BIG_STR = TOO_BIG.toString();
  54 
  55     public static void main(String ... args) {
  56         
  57         //// Tests for parse(), major(), minor(), security(), pre(),
  58         //// build(), opt(), version(), toString()
  59         //   v                          M     m sec pre bld opt
  60 
  61         // $VNUM
  62         test("9",                       9,    0, 0, "", 0, "");
  63         test("9.1",                     9,    1, 0, "", 0, "");
  64         test("9.0.1",                   9,    0, 1, "", 0, "");
  65         test("404.1.2",                 404,  1, 2, "", 0, "");
  66         test("9.1.2.3",                 9,    1, 2, "", 0, "");
  67         test("1000.0.0.0.0.0.99999999", 1000, 0, 0, "", 0, "");
  68 
  69         tryCatch(null,    NPE);
  70         tryCatch("",      IAE);
  71         tryCatch("foo",   IAE);
  72         tryCatch("7a",    IAE);
  73         tryCatch("0",     IAE);
  74         tryCatch("09",    IAE);
  75         tryCatch("9.0",   IAE);
  76         tryCatch("9.0.",  IAE);
  77         tryCatch("1.9,1", IAE);
  78         tryCatch(TOO_BIG_STR, NFE);
  79 
  80         // $PRE
  81         test("9-ea",       9, 0, 0, "ea",       0, "");
  82         test("9-internal", 9, 0, 0, "internal", 0, "");
  83         test("9-0",        9, 0, 0, "0",        0, "");
  84         test("9.2.7-8",    9, 2, 7, "8",        0, "");
  85         test("1-ALL",      1, 0, 0, "ALL",      0, "");
  86         test("2.3.4.5-1a", 2, 3, 4, "1a",       0, "");
  87         test("1-" + TOO_BIG_STR, 1, 0, 0, TOO_BIG_STR, 0, "");
  88 
  89         tryCatch("3.14159-",  IAE);
  90         tryCatch("3.14159-%", IAE);
  91 
  92         // $BUILD
  93         test("9+0",            9, 0,  0,  "",      0,       "");
  94         test("3.14+9999900",   3, 14, 0,  "",      9999900, "");
  95         test("9-pre+105",      9, 0,  0,  "pre",   105,     "");
  96         test("6.0.42-8beta+4", 6, 0,  42, "8beta", 4,       "");
  97 
  98         tryCatch("9+",     IAE);
  99         tryCatch("7+a",    IAE);
 100         tryCatch("9+00",   IAE);
 101         tryCatch("4.2+01", IAE);
 102         tryCatch("4.2+1a", IAE);
 103         tryCatch("1+" + TOO_BIG_STR, NFE);
 104 
 105         // $OPT
 106         test("9+-foo",          9,   0, 0, "",       0,  "foo");
 107         test("42+---bar",       42,  0, 0, "",       0,  "--bar");
 108         test("2.91+-8061493-",  2,  91, 0, "",       0,  "8061493-");
 109         test("24+-foo.bar",     24,  0, 0, "",       0,  "foo.bar");
 110         test("9-ribbit+17-...", 9,   0, 0, "ribbit", 17, "...");
 111         test("7+1-" + TOO_BIG_STR, 7,0, 0, "",       1,  TOO_BIG_STR);
 112 
 113         tryCatch("1.4142+-",  IAE);
 114         tryCatch("2.9979+-%", IAE);
 115 
 116         //// Test for current()
 117         testCurrent();
 118 
 119         //// Test for equals{IgnoreOpt}?(), hashCode(), compareTo{IgnoreOpt}?()
 120         // compare: after "<" == -1, equal == 0, before ">" == 1
 121         //      v0            v1                  eq     eqNO  cmp  cmpNO
 122         testEHC("9",          "9",                true,  true,   0,    0);
 123 
 124         testEHC("8",          "9",                false, false, -1,   -1);
 125         testEHC("9",          "10",               false, false, -1,   -1);
 126         testEHC("9",          "8",                false, false,  1,    1);
 127 
 128         // $OPT comparison
 129         testEHC("9",          "9+-oink",          false, true,  -1,    0);
 130         testEHC("9+-ribbit",  "9+-moo",           false, true,   1,    0);
 131         testEHC("9-quack+-ribbit", 
 132                               "9-quack+-moo",     false, true,   1,    0);
 133         testEHC("9.1+7",      "9.1+7-moo-baa-la", false, true,  -1,    0);
 134 
 135         // numeric vs. non-numeric $PRE 
 136         testEHC("9.1.1.2-2a", "9.1.1.2-12",       false, false,  1,    1);
 137         testEHC("9.1.1.2-12", "9.1.1.2-4",        false, false,  1,    1);
 138 
 139         testEHC("27.16",      "27.16+120",        false, false,  1,    1);
 140         testEHC("10",         "10-ea",            false, false,  1,    1);
 141         testEHC("10.1+1",     "10.1-ea+1",        false, false,  1,    1);
 142         testEHC("10.0.1+22",  "10.0.1+21",        false, false,  1,    1);
 143 
 144         // numeric vs. non-numeric $PRE 
 145         testEHC("9.1.1.2-12", "9.1.1.2-a2",       false, false, -1,   -1);
 146         testEHC("9.1.1.2-1",  "9.1.1.2-4",        false, false, -1,   -1);
 147 
 148         testEHC("9-internal", "9",                false, false, -1,   -1);
 149         testEHC("9-ea+120",   "9+120",            false, false, -1,   -1);
 150         testEHC("9-ea+120",   "9+120",            false, false, -1,   -1);
 151         testEHC("9+101",      "9",                false, false, -1,   -1);
 152         testEHC("9+101",      "9+102",            false, false, -1,   -1);
 153         testEHC("1.9-ea",     "9-ea",             false, false, -1,   -1);
 154 
 155         if (fail != 0)
 156             throw new RuntimeException((fail + pass) + " tests: "
 157                                        + fail + " failure(s), first", first);
 158         else
 159             out.println("all " + (fail + pass) + " tests passed");
 160 
 161     }
 162     
 163     private static void test(String s, Integer major, Integer minor, 
 164                              Integer sec, String pre, Integer build,
 165                              String opt) 
 166     {
 167         Version v = testParse(s);
 168 
 169         testStr(v.toString(), s);
 170         
 171         testInt(v.major(), major);
 172         testInt(v.minor(), minor);
 173         testInt(v.security(), sec);
 174         testStr((v.pre().isPresent() ? v.pre().get() : ""), pre);
 175         testInt((v.build().isPresent() ? v.build().get() : 0), build);
 176         testStr((v.optional().isPresent() ? v.optional().get() : ""), opt);
 177 
 178         testVersion(v.version(), s);
 179     }
 180 
 181     private static Version testParse(String s) {
 182         Version v = Version.parse(s);
 183         pass();
 184         return v;
 185     }
 186 
 187     private static void testInt(int got, int exp) {
 188         if (got != exp) {
 189             fail("testInt()", Integer.toString(exp), Integer.toString(got));
 190         } else {
 191             pass();
 192         }
 193      }
 194 
 195     private static void testStr(String got, String exp) {
 196         if (!got.equals(exp)) {
 197             fail("testStr()", exp, got);
 198         } else {
 199             pass();
 200         }
 201     }
 202 
 203     private static void tryCatch(String s, Class<? extends Throwable> ex) {
 204         Throwable t = null;
 205         try {
 206             Version.parse(s);
 207         } catch (Throwable x) {
 208             if (ex.isAssignableFrom(x.getClass())) {
 209                 t = x;
 210             } else
 211                 x.printStackTrace();
 212         }
 213         if ((t == null) && (ex != null))
 214             fail(s, ex);
 215         else
 216             pass();
 217     }
 218 
 219     private static void testCurrent() {
 220         Version current = Version.current();
 221         String javaVer = System.getProperty("java.version");
 222 
 223         // java.version == $VNUM(\-$PRE)
 224         String [] ver = javaVer.split("-");
 225         List<Integer> javaVerVNum
 226             = Arrays.stream(ver[0].split("\\."))
 227             .map(v -> Integer.parseInt(v))
 228             .collect(Collectors.toList());
 229         if (!javaVerVNum.equals(current.version())) {
 230             fail("testCurrent() version()", javaVerVNum.toString(), 
 231                  current.version().toString());
 232         } else {
 233             pass();
 234         }
 235 
 236         Optional<String> javaVerPre
 237             = (ver.length == 2) 
 238             ? Optional.ofNullable(ver[1]) 
 239             : Optional.empty();
 240         if (!javaVerPre.equals(current.pre())) {
 241             fail("testCurrent() pre()", javaVerPre.toString(), 
 242                  current.pre().toString());
 243         } else {
 244             pass();
 245         }
 246 
 247         testEHC(current.toString(), javaVer, true, true, 0, 0);
 248     }
 249 
 250     private static void testVersion(List<Integer> vnum, String s) {
 251         List<Integer> svnum = new ArrayList<Integer>();
 252         StringBuilder sb = new StringBuilder();
 253         for (int i = 0; i < s.length(); i++) {
 254             Character c = s.charAt(i);
 255             if (Character.isDigit(c)) {
 256                 sb.append(c);
 257             } else {
 258                 svnum.add(Integer.parseInt(sb.toString()));
 259                 sb = new StringBuilder();
 260                 if (c == '+' || c == '-') {
 261                     break;
 262                 }
 263             }
 264         }
 265         if (sb.length() > 0) {
 266             svnum.add(Integer.parseInt(sb.toString()));
 267         }
 268 
 269         if (!svnum.equals(vnum)) {
 270             fail("testVersion() equals()", svnum.toString(), vnum.toString());
 271         } else {
 272             pass();
 273         }
 274     }
 275 
 276     private static void testEHC(String s0, String s1, boolean eq, boolean eqNO,
 277                                 int cmp, int cmpNO) 
 278     {
 279         Version v0 = Version.parse(s0);
 280         Version v1 = Version.parse(s1);
 281 
 282         testEquals(v0, v1, eq);
 283         testEqualsNO(v0, v1, eqNO);
 284 
 285         testHashCode(v0, v1, eq);
 286 
 287         testCompare(v0, v1, cmp);
 288         testCompareNO(v0, v1, cmpNO);
 289     }
 290 
 291     private static void testEqualsNO(Version v0, Version v1, boolean eq) {
 292         if ((eq && !v0.equalsIgnoreOpt(v1)) 
 293             || (!eq && v0.equalsIgnoreOpt(v1))) {
 294             fail("equalsIgnoreOpt() " + Boolean.toString(eq),
 295                  v0.toString(), v1.toString());
 296         } else {
 297             pass();
 298         }
 299     }
 300 
 301     private static void testEquals(Version v0, Version v1, boolean eq) {
 302         if ((eq && !v0.equals(v1)) || (!eq && v0.equals(v1))) {
 303             fail("equals() " + Boolean.toString(eq),
 304                  v0.toString(), v1.toString());
 305         } else {
 306             pass();
 307         }
 308     }
 309 
 310     private static void testHashCode(Version v0, Version v1, boolean eq) {
 311         int h0 = v0.hashCode();
 312         int h1 = v1.hashCode();
 313         if (eq) {
 314             testInt(h0, h1);
 315         } else if (h0 == h1) {
 316             fail(String.format("hashCode() %s", h0),
 317                  Integer.toString(h0),
 318                  Integer.toString(h1));
 319         } else { // !eq && (h0 != h1)
 320             pass();
 321         }
 322     }
 323 
 324     private static void testCompareNO(Version v0, Version v1, int compare) 
 325     {
 326         try {
 327             Method m = VERSION.getMethod("compareToIgnoreOpt", VERSION);
 328             int cmp = (int) m.invoke(v0, v1);
 329             checkCompare(v0, v1, compare, cmp);
 330         } catch (IllegalAccessException | InvocationTargetException |
 331                  NoSuchMethodException ex) {
 332             fail(String.format("compareToIgnoreOpt() invocation: %s", 
 333                                ex.getClass()), 
 334                  null);
 335         }
 336     }
 337 
 338     private static void testCompare(Version v0, Version v1, int compare) {
 339         try {
 340             Method m = VERSION.getMethod("compareTo", VERSION);
 341             int cmp = (int) m.invoke(v0, v1);
 342             checkCompare(v0, v1, compare, cmp);
 343         } catch (IllegalAccessException | InvocationTargetException |
 344                  NoSuchMethodException ex) {
 345             fail(String.format("compareTo() invocation: %s", ex.getClass()), 
 346                  null);
 347         }
 348     }
 349 
 350     private static void checkCompare(Version v0, Version v1, 
 351                                      int compare, int cmp) 
 352     {
 353         if (((cmp == 0) && (compare == 0))
 354             || (compare == (cmp / Math.abs(cmp == 0 ? 1 : cmp)))) {
 355             pass();
 356         } else {
 357             fail(String.format("compare() (cmp = %s) (compare = %s)", 
 358                                cmp, compare),
 359                  v0.toString(), v1.toString());
 360         }
 361     }
 362 
 363     private static int fail = 0;
 364     private static int pass = 0;
 365 
 366     private static Throwable first;
 367 
 368     static void pass() {
 369         pass++;
 370     }
 371 
 372     static void fail(String fs, Class ex) {
 373         String s = "'" + fs + "'";
 374         if (ex != null)
 375             s += ": " + ex.getName() + " not thrown";
 376         if (first == null)
 377             setFirst(s);
 378         System.err.println("FAILED: " + s);
 379         fail++;
 380     }
 381 
 382     static void fail(String t, String exp, String got) {
 383         String s = t + ": Expected '" + exp + "', got '" + got + "'";
 384         if (first == null)
 385             setFirst(s);
 386         System.err.println("FAILED: " + s);
 387         fail++;
 388      }
 389 
 390     private static void setFirst(String s) {
 391         try {
 392             throw new RuntimeException(s);
 393         } catch (RuntimeException x) {
 394             first = x;
 395         }
 396     }
 397 }