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