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 package optionsvalidation;
  25 
  26 import java.math.BigInteger;
  27 import java.util.ArrayList;
  28 import java.util.List;
  29 import jdk.test.lib.Platform;
  30 
  31 public class IntJVMOption extends JVMOption {
  32 
  33     enum IntType {
  34 
  35         INTX,
  36         UINTX,
  37         UINT64_T
  38     }
  39 
  40     private static final BigInteger MIN_LONG;
  41     private static final BigInteger MAX_LONG;
  42     private static final BigInteger MAX_UNSIGNED_LONG;
  43     private static final BigInteger MAX_UNSIGNED_LONG_64;
  44     private static final BigInteger MINUS_ONE = new BigInteger("-1");
  45     private static final BigInteger MAX_4_BYTE_INT_PLUS_ONE = new BigInteger("2147483648");
  46     private static final BigInteger MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE = new BigInteger("4294967296");
  47 
  48     /**
  49      * Mininum option value
  50      */
  51     private BigInteger min;
  52     /**
  53      * Maximum option value
  54      */
  55     private BigInteger max;
  56 
  57     /**
  58      * Is this value is signed or unsigned
  59      */
  60     private boolean unsigned;
  61 
  62     /**
  63      * Is this value is 64 bit unsigned
  64      */
  65     private boolean uint64 = false;
  66 
  67     static {
  68         if (Platform.is32bit()) {
  69             MIN_LONG = new BigInteger(String.valueOf(Integer.MIN_VALUE));
  70             MAX_LONG = new BigInteger(String.valueOf(Integer.MAX_VALUE));
  71             MAX_UNSIGNED_LONG = MAX_LONG.multiply(new BigInteger("2")).add(BigInteger.ONE);
  72         } else {
  73             MIN_LONG = new BigInteger(String.valueOf(Long.MIN_VALUE));
  74             MAX_LONG = new BigInteger(String.valueOf(Long.MAX_VALUE));
  75             MAX_UNSIGNED_LONG = MAX_LONG.multiply(new BigInteger("2")).add(BigInteger.ONE);
  76         }
  77 
  78         MAX_UNSIGNED_LONG_64 = (new BigInteger(String.valueOf(Long.MAX_VALUE)))
  79                 .multiply(new BigInteger("2")).add(BigInteger.ONE);
  80     }
  81 
  82     /**
  83      * Default constructor. Init min and max with minimum int and maximum int.
  84      */
  85     private IntJVMOption() {
  86         min = MIN_LONG;
  87         max = MAX_LONG;
  88         unsigned = false;
  89         uint64 = false;
  90     }
  91 
  92     /**
  93      * Initialize new integer option with given type. Type can be: INTX -
  94      * integer signed option UINTX - unsigned integer option UINT64_T - unsigned
  95      * 64 bit integer option
  96      *
  97      * @param name
  98      * @param type
  99      */
 100     IntJVMOption(String name, IntType type) {
 101         this();
 102         this.name = name;
 103 
 104         switch (type) {
 105             case UINT64_T:
 106                 uint64 = true;
 107             case UINTX:
 108                 unsigned = true;
 109                 break;
 110         }
 111 
 112         if (unsigned) {
 113             min = BigInteger.ZERO;
 114             max = MAX_UNSIGNED_LONG;
 115         }
 116 
 117         if (uint64) {
 118             max = MAX_UNSIGNED_LONG_64;
 119         }
 120     }
 121 
 122     /**
 123      * Initialize integer option with passed name, min and max values. Min and
 124      * max are string because they can be very big, bigger than long.
 125      *
 126      * @param name Name of the option
 127      * @param min Minimum value of the option
 128      * @param max Maximum value of the option
 129      */
 130     public IntJVMOption(String name, String min, String max) {
 131         this();
 132         this.name = name;
 133         this.min = new BigInteger(min);
 134         this.max = new BigInteger(max);
 135     }
 136 
 137     /**
 138      * Set new minimum option value
 139      *
 140      * @param min New minimum value
 141      */
 142     @Override
 143     void setMin(String min) {
 144         this.min = new BigInteger(min);
 145     }
 146 
 147     /**
 148      * Get string with minimum value of the option
 149      *
 150      * @return String with minimum value of the option
 151      */
 152     @Override
 153     String getMin() {
 154         return min.toString();
 155     }
 156 
 157     /**
 158      * Set new maximum option value
 159      *
 160      * @param max New maximum value
 161      */
 162     @Override
 163     void setMax(String max) {
 164         this.max = new BigInteger(max);
 165     }
 166 
 167     /**
 168      * Get string with maximum value of the option
 169      *
 170      * @return String with maximum value of the option
 171      */
 172     @Override
 173     String getMax() {
 174         return max.toString();
 175     }
 176 
 177     /**
 178      * Return list of strings with valid option values which used for testing
 179      * using jcmd, attach and etc.
 180      *
 181      * @return List of strings which contain valid values for option
 182      */
 183     @Override
 184     protected List<String> getValidValues() {
 185         List<String> validValues = new ArrayList<>();
 186 
 187         validValues.add(min.toString());
 188         validValues.add(max.toString());
 189 
 190         if ((min.compareTo(MINUS_ONE) == -1) && (max.compareTo(MINUS_ONE) == 1)) {
 191             /*
 192              * Add -1 as valid value if min is less than -1 and max is greater than -1
 193              */
 194             validValues.add("-1");
 195         }
 196 
 197         if ((min.compareTo(BigInteger.ZERO) == -1) && (max.compareTo(BigInteger.ZERO) == 1)) {
 198             /*
 199              * Add 0 as valid value if min is less than 0 and max is greater than 0
 200              */
 201             validValues.add("0");
 202         }
 203         if ((min.compareTo(BigInteger.ONE) == -1) && (max.compareTo(BigInteger.ONE) == 1)) {
 204             /*
 205              * Add 1 as valid value if min is less than 1 and max is greater than 1
 206              */
 207             validValues.add("1");
 208         }
 209 
 210         if (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1) {
 211             /* 
 212              * Check for overflow when flag is assigned to the 
 213              * 4 byte int variable
 214              */
 215             validValues.add(MAX_4_BYTE_INT_PLUS_ONE.toString());
 216         }
 217 
 218         if (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1) {
 219             /* 
 220              * Check for overflow when flag is assigned to the 
 221              * 4 byte unsigned int variable
 222              */
 223             validValues.add(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE.toString());
 224         }
 225 
 226         return validValues;
 227     }
 228 
 229     /**
 230      * Return list of strings with invalid option values which used for testing
 231      * using jcmd, attach and etc.
 232      *
 233      * @return List of strings which contain invalid values for option
 234      */
 235     @Override
 236     protected List<String> getInvalidValues() {
 237         List<String> invalidValues = new ArrayList<>();
 238 
 239         if (min.compareTo(MIN_LONG) != 0) {
 240             invalidValues.add(min.subtract(BigInteger.ONE).toString());
 241         }
 242 
 243         if (!unsigned && (max.compareTo(MAX_LONG) != 0)) {
 244             invalidValues.add(max.add(BigInteger.ONE).toString());
 245         }
 246 
 247         if (unsigned
 248                 && ((!uint64 && (max.compareTo(MAX_UNSIGNED_LONG) != 0))
 249                 || (uint64 && (max.compareTo(MAX_UNSIGNED_LONG_64) != 0)))) {
 250             invalidValues.add(max.add(BigInteger.ONE).toString());
 251         }
 252 
 253         return invalidValues;
 254     }
 255 
 256     /**
 257      * Return expected error message for option with value "value" when it used
 258      * on command line with passed value
 259      *
 260      * @param value Option value
 261      * @return Expected error message
 262      */
 263     @Override
 264     protected String getErrorMessageCommandLine(String value) {
 265         String errorMsg;
 266 
 267         if (withRange) {
 268             /* Option have defined range in VM */
 269             if (unsigned && ((new BigInteger(value)).compareTo(BigInteger.ZERO) < 0)) {
 270                 /*
 271                  * Special case for unsigned options with lower range equal to 0. If 
 272                  * passed value is negative then error will be catched earlier for
 273                  * such options. Thus use different error message.
 274                  */
 275                 errorMsg = String.format("Improperly specified VM option '%s=%s'", name, value);
 276             } else {
 277                 errorMsg = String.format("%s=%s is outside the allowed range [ %s ... %s ]",
 278                         name, value, min.toString(), max.toString());
 279             }
 280         } else {
 281             errorMsg = "";
 282         }
 283 
 284         return errorMsg;
 285     }
 286 }