2 * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
28 import java.util.Arrays;
29 import org.junit.AfterClass;
30 import org.junit.BeforeClass;
31 import org.junit.Test;
32 import static org.junit.Assert.*;
38 public class BytecodeNameTest {
40 public BytecodeNameTest() {
44 public static void setUpClass() throws Exception {
48 public static void tearDownClass() throws Exception {
51 static String[][] SAMPLES = {
55 {"\\=ba\\-%z", "ba\\%z"},
56 {"\\=ba\\--z", "ba\\-z"},
58 {"\\==\\|\\=", "=/\\="},
68 static String[][] canonicalSamples() {
69 int ndc = DANGEROUS_CHARS.length();
70 String[][] res = new String[2*ndc][];
71 for (int i = 0; i < ndc; i++) {
72 char dc = DANGEROUS_CHARS.charAt(i);
73 char rc = REPLACEMENT_CHARS.charAt(i);
75 res[2*i+0] = new String[] { "\\-%", "\\%" };
77 res[2*i+0] = new String[] { "\\"+rc, ""+dc };
79 res[2*i+1] = new String[] { ""+rc, ""+rc };
85 public void testToBytecodeName() {
86 System.out.println("toBytecodeName");
87 testToBytecodeName(SAMPLES);
88 testToBytecodeName(canonicalSamples());
90 public void testToBytecodeName(String[][] samples) {
91 for (String[] sample : samples) {
93 String expResult = sample[0];
94 String result = BytecodeName.toBytecodeName(s);
95 if (!result.equals(expResult))
96 System.out.println(s+" => "+result+" != "+expResult);
97 assertEquals(expResult, result);
102 public void testToSourceName() {
103 System.out.println("toSourceName");
104 testToBytecodeName(SAMPLES);
105 testToBytecodeName(canonicalSamples());
107 public void testToSourceName(String[][] samples) {
108 for (String[] sample : samples) {
109 String s = sample[0];
110 String expResult = sample[1];
111 String result = BytecodeName.toBytecodeName(s);
112 assertEquals(expResult, result);
116 Object[][] PARSE_SAMPLES = {
120 {":foo", ':', "foo"},
122 {"java/lang/String", "java", '/', "lang", '/', "String"},
123 {"<init>", '<', "init", '>'},
124 {"foo/bar$:baz", "foo", '/', "bar", '$', ':', "baz"},
125 {"::\\=:foo:\\=bar\\!baz", ':', ':', "", ':', "foo", ':', "bar:baz"},
129 public void testParseBytecodeName() {
130 System.out.println("parseBytecodeName");
131 for (Object[] sample : PARSE_SAMPLES)
132 testParseBytecodeName((String) sample[0], Arrays.copyOfRange(sample, 1, sample.length));
133 for (String[] sample : SAMPLES) {
134 for (char dc : DANGEROUS_CHARS.toCharArray()) {
135 if (dc == '\\') continue;
136 testParseBytecodeName(sample[0], sample[1]);
137 testParseBytecodeName(dc+sample[0], dc, sample[1]);
138 testParseBytecodeName(dc+sample[0]+dc, dc, sample[1], dc);
139 testParseBytecodeName(sample[0]+dc, sample[1], dc);
143 public void testParseBytecodeName(String s, Object... expResult) {
144 Object[] result = BytecodeName.parseBytecodeName(s);
145 if (!Arrays.equals(expResult, result))
146 System.out.println(s+" => "+Arrays.toString(result)+" != "+Arrays.toString(expResult));
147 assertArrayEquals(expResult, result);
151 public void testUnparseBytecodeName() {
152 System.out.println("unparseBytecodeName");
153 for (Object[] sample : PARSE_SAMPLES)
154 testUnparseBytecodeName((String) sample[0], Arrays.copyOfRange(sample, 1, sample.length));
155 for (String[] sample : SAMPLES) {
156 for (char dc : DANGEROUS_CHARS.toCharArray()) {
157 if (dc == '\\') continue;
158 testUnparseBytecodeName(sample[0], sample[1]);
159 testUnparseBytecodeName(dc+sample[0], dc, sample[1]);
160 testUnparseBytecodeName(dc+sample[0]+dc, dc, sample[1], dc);
161 testUnparseBytecodeName(sample[0]+dc, sample[1], dc);
165 public void testUnparseBytecodeName(String expResult, Object... components) {
166 String result = BytecodeName.unparseBytecodeName(components);
167 assertEquals(expResult, result);
170 String[][] DISPLAY_SAMPLES = {
172 {"", "" }, // not "''"
173 {"\\=", "''" }, // not ""
174 {"\\=,\\%,\\=", "',$,\\\\='" },
175 {"\\=.\\%.\\=", "''.'$'.''" },
179 {"java.lang", "java.lang"},
180 {"java.123", "java.'123'"},
181 {"123.lang", "'123'.lang"},
183 {"foo:bar", "foo:bar"},
184 {"\\=foo\\!bar", "'foo:bar'"},
185 {"foo$bar", "foo$bar"},
186 {"\\=foo\\%bar", "'foo$bar'"},
190 public void testToDisplayName() {
191 System.out.println("toDisplayName");
192 for (String[] sample : DISPLAY_SAMPLES) {
193 String s = sample[0];
194 String expResult = sample[1];
195 String result = BytecodeName.toDisplayName(s);
196 if (!result.equals(expResult))
197 System.out.println(s+" => "+result+" != "+expResult);
198 assertEquals(expResult, result);
203 public void testIsSafeBytecodeName() {
204 System.out.println("isSafeBytecodeName");
216 // Unsafe strings start with "":
222 boolean expResult = true;
223 for (String s : strings) {
224 if (s.equals("")) expResult = false;
225 boolean result = BytecodeName.isSafeBytecodeName(s);
226 assertEquals(expResult, result);
231 public void testIsSafeBytecodeChar() {
232 System.out.println("isSafeBytecodeChar");
233 for (char c = 0; c < 500; c++) {
234 boolean expResult = c == '\\' || DANGEROUS_CHARS.indexOf(c) < 0;
235 boolean result = BytecodeName.isSafeBytecodeChar(c);
236 assertEquals(expResult, result);
240 // optional test driver
241 static void main(String[] av) {
242 // If verbose is enabled, quietly check everything.
243 // Otherwise, print the output for the user to check.
244 boolean verbose = false;
248 while (av.length > 0 && av[0].startsWith("-")) {
249 String flag = av[0].intern();
250 av = java.util.Arrays.copyOfRange(av, 1, av.length); // Java 1.6 or later
251 if (flag == "-" || flag == "--") break;
252 else if (flag == "-q")
254 else if (flag == "-v")
256 else if (flag.startsWith("-l"))
257 maxlen = Integer.valueOf(flag.substring(2));
259 throw new Error("Illegal flag argument: "+flag);
263 maxlen = (verbose ? 2 : 4);
264 if (verbose) System.out.println("Note: maxlen = "+maxlen);
267 case 0: av = new String[] {
268 DANGEROUS_CHARS.substring(0) +
269 REPLACEMENT_CHARS.substring(0, 2) +
271 }; // and fall through:
273 char[] cv = av[0].toCharArray();
274 av = new String[cv.length];
277 String s = String.valueOf(c);
278 if (c == 'x') s = "foo"; // tradition...
283 System.out.println("Note: Verbose output mode enabled. Use '-q' to suppress.");
284 Tester t = new Tester();
291 static char ESCAPE_C = '\\';
292 // empty escape sequence to avoid a null name or illegal prefix
293 static char NULL_ESCAPE_C = '=';
294 static String NULL_ESCAPE = ESCAPE_C+""+NULL_ESCAPE_C;
296 static final String DANGEROUS_CHARS = "\\/.;:$[]<>";
297 static final String REPLACEMENT_CHARS = "-|,?!%{}^_";
300 public void testMangler() {
301 System.out.println("(mangler)");
302 Tester t = new Tester();
305 DANGEROUS_CHARS.substring(0) +
306 REPLACEMENT_CHARS.substring(0, 2) +
308 t.tokens = new String[alphabet.length()];
310 for (char c : alphabet.toCharArray())
311 t.tokens[fill++] = String.valueOf(c);
313 System.out.println("tested mangler exhaustively on "+t.map.size()+" strings to length "+t.maxlen);
316 static class Tester {
319 java.util.Map<String,String> map = new java.util.HashMap<String,String>();
322 void test(String stringSoFar, int tokensSoFar) {
324 if (tokensSoFar <= maxlen) {
325 for (String token : tokens) {
326 if (token.length() == 0) continue; // skip empty tokens
327 if (stringSoFar.indexOf(token) != stringSoFar.lastIndexOf(token))
328 continue; // there are already two occs. of this token
329 if (token.charAt(0) == ESCAPE_C && token.length() == 1 && maxlen < 4)
330 test(stringSoFar+token, tokensSoFar); // want lots of \'s
331 else if (tokensSoFar < maxlen)
332 test(stringSoFar+token, tokensSoFar+1);
337 void test(String s) {
338 // for small batches, do not test the null string
339 if (s.length() == 0 && maxlen >=1 && maxlen <= 2) return;
340 String bn = testSourceName(s);
341 if (bn == null) return;
343 //if (verbose) System.out.println(s+" == id");
345 if (verbose) System.out.println(s+" => "+bn+" "+BytecodeName.toDisplayName(bn));
346 String bnbn = testSourceName(bn);
347 if (bnbn == null) return;
348 if (verbose) System.out.println(bn+" => "+bnbn+" "+BytecodeName.toDisplayName(bnbn));
350 String bn3 = testSourceName(bnbn);
351 if (bn3 == null) return;
352 if (verbose) System.out.println(bnbn+" => "+bn3);
357 String testSourceName(String s) {
358 if (map.containsKey(s)) return null;
359 String bn = BytecodeName.toBytecodeName(s);
361 String sn = BytecodeName.toSourceName(bn);
363 String bad = (s+" => "+bn+" != "+sn);
364 if (!verbose) throw new Error("Bad mangling: "+bad);
365 System.out.println("*** "+bad);