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