1 /*
   2  * Copyright (c) 2009, 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  * @bug 6827009
  27  * @summary Positive tests for strings in switch.
  28  * @author  Joseph D. Darcy
  29  */
  30 
  31 public class StringSwitches {
  32 
  33     public static void main(String... args) {
  34         int failures = 0;
  35 
  36         failures += testPileup();
  37         failures += testSwitchingTwoWays();
  38         failures += testNamedBreak();
  39 
  40         if (failures > 0) {
  41             throw new RuntimeException();
  42         }
  43     }
  44 
  45     /*
  46      * A zero length string and all strings consisting only of the
  47      * zero character \u0000 have a hash code of zero.  This method
  48      * maps such strings to the number of times \u0000 appears for 0
  49      * through 6 occurrences.
  50      */
  51     private static int zeroHashes(String s) {
  52         int result = Integer.MAX_VALUE;
  53         switch(s) {
  54         case "":
  55             return 0;
  56 
  57         case "\u0000":
  58             result = 1; break;
  59 
  60         case "\u0000\u0000":
  61             return 2;
  62 
  63         case "\u0000\u0000\u0000":
  64             result = 3; break;
  65 
  66         case "\u0000\u0000\u0000\u0000":
  67             return 4;
  68 
  69         case "\u0000\u0000\u0000\u0000\u0000":
  70             result = 5; break;
  71 
  72         case "\u0000\u0000\u0000\u0000\u0000\u0000":
  73             return 6;
  74 
  75         default:
  76             result = -1;
  77         }
  78         return result;
  79     }
  80 
  81     private static int testPileup() {
  82         int failures = 0;
  83         String zero = "";
  84         for(int i = 0; i <= 6; i++, zero += "\u0000") {
  85             int result = zeroHashes(zero);
  86             if (result != i) {
  87                 failures++;
  88                 System.err.printf("For string \"%s\" unexpectedly got %d instead of %d%n.",
  89                                    zero, result, i);
  90             }
  91         }
  92 
  93         if (zeroHashes("foo") != -1) {
  94             failures++;
  95             System.err.println("Failed to get -1 for input string.");
  96         }
  97 
  98         return failures;
  99     }
 100 
 101     /**
 102      * Verify that a switch on an enum and a switch with the same
 103      * structure on the string name of an enum compute equivalent
 104      * values.
 105      */
 106     private static int testSwitchingTwoWays() {
 107         int failures = 0;
 108 
 109         for(MetaSynVar msv : MetaSynVar.values()) {
 110             int enumResult = enumSwitch(msv);
 111             int stringResult = stringSwitch(msv.name());
 112 
 113             if (enumResult != stringResult) {
 114                 failures++;
 115                 System.err.printf("One value %s, computed 0x%x with the enum switch " +
 116                                   "and 0x%x with the string one.%n",
 117                                   msv, enumResult, stringResult);
 118             }
 119         }
 120 
 121         return failures;
 122     }
 123 
 124     private static enum MetaSynVar {
 125         FOO,
 126         BAR,
 127         BAZ,
 128         QUX,
 129         QUUX,
 130         QUUUX,
 131         MUMBLE,
 132         FOOBAR;
 133     }
 134 
 135     private static int enumSwitch(MetaSynVar msv) {
 136         int result = 0;
 137         switch(msv) {
 138         case FOO:
 139             result |= (1<<0);
 140             // fallthrough:
 141 
 142         case BAR:
 143         case BAZ:
 144             result |= (1<<1);
 145             break;
 146 
 147         default:
 148             switch(msv) {
 149             case QUX:
 150                 result |= (1<<2);
 151                 break;
 152 
 153             case QUUX:
 154                 result |= (1<<3);
 155 
 156             default:
 157                 result |= (1<<4);
 158             }
 159             result |= (1<<5);
 160             break;
 161 
 162         case MUMBLE:
 163             result |= (1<<6);
 164             return result;
 165 
 166         case FOOBAR:
 167             result |= (1<<7);
 168             break;
 169         }
 170         result |= (1<<8);
 171         return result;
 172     }
 173 
 174     private static int stringSwitch(String msvName) {
 175         int result = 0;
 176         switch(msvName) {
 177         case "FOO":
 178             result |= (1<<0);
 179             // fallthrough:
 180 
 181         case "BAR":
 182         case "BAZ":
 183             result |= (1<<1);
 184             break;
 185 
 186         default:
 187             switch(msvName) {
 188             case "QUX":
 189                 result |= (1<<2);
 190                 break;
 191 
 192             case "QUUX":
 193                 result |= (1<<3);
 194 
 195             default:
 196                 result |= (1<<4);
 197             }
 198             result |= (1<<5);
 199             break;
 200 
 201         case "MUMBLE":
 202             result |= (1<<6);
 203             return result;
 204 
 205         case "FOOBAR":
 206             result |= (1<<7);
 207             break;
 208         }
 209         result |= (1<<8);
 210         return result;
 211     }
 212 
 213     private static int testNamedBreak() {
 214         int failures = 0;
 215         String[] testStrings  = {"a",       "b",  "c",       "d",      "e"};
 216         int[]    testExpected = { 0b101011, 0b101, 0b100001, 0b101000, 0b10000};
 217 
 218         for(int i = 0; i < testStrings.length; i++) {
 219             int expected = testExpected[i];
 220             int result = namedBreak(testStrings[i]);
 221 
 222             if (result != expected) {
 223                 failures++;
 224 
 225                 System.err.printf("On input %s, got %d instead of %d.%n",
 226                                   testStrings[i], result, expected);
 227             }
 228         }
 229 
 230         return failures;
 231     }
 232 
 233     private static int namedBreak(String s) {
 234         int result = 0;
 235         outer: switch(s) {
 236         case "a":
 237         case "b":
 238         case "c":
 239             result |= (1<<0);
 240         inner: switch(s + s) {
 241             case "aa":
 242                 result |= (1<<1);
 243                 break inner;
 244 
 245             case "cc":
 246                 break outer;
 247 
 248             default:
 249                 result |= (1<<2);
 250                 return result;
 251             }
 252 
 253         case "d":
 254             result |= (1<<3);
 255             break outer;
 256 
 257         default:
 258             return result |= (1<<4);
 259         }
 260         result |= (1<<5);
 261         return result;
 262     }
 263 }