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 }