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 31public 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} 280