netbeans/meth/test/sun/dyn/util/BytecodeNameTest.java
author jrose
Fri Aug 07 18:13:21 2009 -0700 (3 months ago)
changeset 28 5958143570a7
parent 277b03cdfd6265
permissions -rw-r--r--
meth: more sun.dyn.util.BytecodeName test cases
        1 /*
        2  * Copyright 2009 Sun Microsystems, Inc.  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.  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.
       10  * 
       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).
       16  * 
       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.
       20  * 
       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
       23  * have any questions.
       24  */
       25 
       26 package sun.dyn.util;
       27 
       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.*;
       33 
       34 /**
       35  *
       36  * @author jrose
       37  */
       38 public class BytecodeNameTest {
       39 
       40     public BytecodeNameTest() {
       41     }
       42 
       43     @BeforeClass
       44     public static void setUpClass() throws Exception {
       45     }
       46 
       47     @AfterClass
       48     public static void tearDownClass() throws Exception {
       49     }
       50 
       51     static String[][] SAMPLES = {
       52         // mangled, source
       53         {"foo", "foo"},
       54         {"ba\\r", "ba\\r"},
       55         {"\\=ba\\-%z", "ba\\%z"},
       56         {"\\=ba\\--z", "ba\\-z"},
       57         {"=\\=", "=\\="},
       58         {"\\==\\|\\=", "=/\\="},
       59         {"\\|\\=", "/\\="},
       60         {"\\=ba\\!", "ba:"},
       61         {"\\|", "/"},
       62         {"\\", "\\"},
       63         {"\\\\%", "\\$"},
       64         {"\\\\", "\\\\"},
       65         {"\\=", ""}
       66     };
       67 
       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);
       74             if (dc == '\\') {
       75                 res[2*i+0] = new String[] { "\\-%", "\\%" };
       76             } else {
       77                 res[2*i+0] = new String[] { "\\"+rc, ""+dc };
       78             }
       79             res[2*i+1] = new String[] { ""+rc, ""+rc };
       80         }
       81         return res;
       82     }
       83 
       84     @Test
       85     public void testToBytecodeName() {
       86         System.out.println("toBytecodeName");
       87         testToBytecodeName(SAMPLES);
       88         testToBytecodeName(canonicalSamples());
       89     }
       90     public void testToBytecodeName(String[][] samples) {
       91         for (String[] sample : samples) {
       92             String s = sample[1];
       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);
       98         }
       99     }
      100 
      101     @Test
      102     public void testToSourceName() {
      103         System.out.println("toSourceName");
      104         testToBytecodeName(SAMPLES);
      105         testToBytecodeName(canonicalSamples());
      106     }
      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);
      113         }
      114     }
      115 
      116     Object[][] PARSE_SAMPLES = {
      117         {""},
      118         {"/", '/'},
      119         {"\\", "\\"},
      120         {":foo", ':', "foo"},
      121         {"\\=ba\\!", "ba:"},
      122         {"java/lang/String", "java", '/', "lang", '/', "String"},
      123         {"<init>", '<', "init", '>'},
      124         {"foo/bar$:baz", "foo", '/', "bar", '$', ':', "baz"},
      125         {"::\\=:foo:\\=bar\\!baz", ':', ':', "", ':', "foo", ':', "bar:baz"},
      126     };
      127 
      128     @Test
      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);
      140             }
      141         }
      142     }
      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);
      148     }
      149 
      150     @Test
      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);
      162             }
      163         }
      164     }
      165     public void testUnparseBytecodeName(String expResult, Object... components) {
      166         String result = BytecodeName.unparseBytecodeName(components);
      167         assertEquals(expResult, result);
      168     }
      169 
      170     String[][] DISPLAY_SAMPLES = {
      171         {"foo", "foo"},
      172         {"", "" }, // not "''"
      173         {"\\=", "''" }, // not ""
      174         {"\\=,\\%,\\=", "',$,\\\\='" },
      175         {"\\=.\\%.\\=", "''.'$'.''" },
      176         {"123", "'123'"},
      177         {"'", "'\\''"},
      178         {"\\", "'\\\\'"},
      179         {"java.lang", "java.lang"},
      180         {"java.123", "java.'123'"},
      181         {"123.lang", "'123'.lang"},
      182         {"\\|", "'/'"},
      183         {"foo:bar", "foo:bar"},
      184         {"\\=foo\\!bar", "'foo:bar'"},
      185         {"foo$bar", "foo$bar"},
      186         {"\\=foo\\%bar", "'foo$bar'"},
      187     };
      188 
      189     @Test
      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);
      199         }
      200     }
      201 
      202     @Test
      203     public void testIsSafeBytecodeName() {
      204         System.out.println("isSafeBytecodeName");
      205         String[] strings = {
      206             // Safe strings:
      207             "foo",
      208             "\\",
      209             "\\foo",
      210             "\\=foo",
      211             "foo\\",
      212             "foo\\%",
      213             "fo\\o",
      214             "fo\\%o",
      215             "123",
      216             // Unsafe strings start with "":
      217             "",
      218             "foo:bar",
      219             "<init>",
      220             "/",
      221         };
      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);
      227         }
      228     }
      229 
      230     @Test
      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);
      237         }
      238     }
      239 
      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;
      245 
      246         int maxlen = 0;
      247 
      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")
      253                 verbose = false;
      254             else if (flag == "-v")
      255                 verbose = true;
      256             else if (flag.startsWith("-l"))
      257                 maxlen = Integer.valueOf(flag.substring(2));
      258             else
      259                 throw new Error("Illegal flag argument: "+flag);
      260         }
      261 
      262         if (maxlen == 0)
      263             maxlen = (verbose ? 2 : 4);
      264         if (verbose)  System.out.println("Note: maxlen = "+maxlen);
      265 
      266         switch (av.length) {
      267         case 0: av = new String[] {
      268                     DANGEROUS_CHARS.substring(0) +
      269                     REPLACEMENT_CHARS.substring(0, 2) +
      270                     NULL_ESCAPE + "x"
      271                 }; // and fall through:
      272         case 1:
      273             char[] cv = av[0].toCharArray();
      274             av = new String[cv.length];
      275             int avp = 0;
      276             for (char c : cv) {
      277                 String s = String.valueOf(c);
      278                 if (c == 'x')  s = "foo";  // tradition...
      279                 av[avp++] = s;
      280             }
      281         }
      282         if (verbose)
      283             System.out.println("Note: Verbose output mode enabled.  Use '-q' to suppress.");
      284         Tester t = new Tester();
      285         t.maxlen = maxlen;
      286         t.verbose = verbose;
      287         t.tokens = av;
      288         t.test("", 0);
      289     }
      290 
      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;
      295 
      296     static final String DANGEROUS_CHARS   = "\\/.;:$[]<>";
      297     static final String REPLACEMENT_CHARS =  "-|,?!%{}^_";
      298 
      299     @Test
      300     public void testMangler() {
      301         System.out.println("(mangler)");
      302         Tester t = new Tester();
      303         t.maxlen = 4;
      304         String alphabet =
      305             DANGEROUS_CHARS.substring(0) +
      306             REPLACEMENT_CHARS.substring(0, 2) +
      307             NULL_ESCAPE + "x";
      308         t.tokens = new String[alphabet.length()];
      309         int fill = 0;
      310         for (char c : alphabet.toCharArray())
      311             t.tokens[fill++] = String.valueOf(c);
      312         t.test("", 0);
      313         System.out.println("tested mangler exhaustively on "+t.map.size()+" strings to length "+t.maxlen);
      314     }
      315 
      316     static class Tester {
      317         boolean verbose;
      318         int maxlen;
      319         java.util.Map<String,String> map = new java.util.HashMap<String,String>();
      320         String[] tokens;
      321 
      322         void test(String stringSoFar, int tokensSoFar) {
      323             test(stringSoFar);
      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);
      333                 }
      334             }
      335         }
      336 
      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;
      342             if (bn == s) {
      343                 //if (verbose)  System.out.println(s+" == id");
      344             } else {
      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));
      349                 /*
      350                 String bn3 = testSourceName(bnbn);
      351                 if (bn3 == null)  return;
      352                 if (verbose)  System.out.println(bnbn+" => "+bn3);
      353                 */
      354             }
      355         }
      356 
      357         String testSourceName(String s) {
      358             if (map.containsKey(s))  return null;
      359             String bn = BytecodeName.toBytecodeName(s);
      360             map.put(s, bn);
      361             String sn = BytecodeName.toSourceName(bn);
      362             if (!sn.equals(s)) {
      363                 String bad = (s+" => "+bn+" != "+sn);
      364                 if (!verbose)  throw new Error("Bad mangling: "+bad);
      365                 System.out.println("*** "+bad);
      366                 return null;
      367             }
      368             return bn;
      369         }
      370     }
      371 }