Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright 2013, Google Inc.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  *     * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *     * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *     * Neither the name of Google Inc. nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 package org.jf.util;
     33 
     34 import com.google.common.base.Strings;
     35 import com.google.common.io.Files;
     36 import junit.framework.Assert;
     37 import org.junit.Test;
     38 
     39 import java.io.File;
     40 import java.nio.charset.Charset;
     41 
     42 public class ClassFileNameHandlerTest {
     43     private final Charset UTF8 = Charset.forName("UTF-8");
     44 
     45     @Test
     46     public void test1ByteEncodings() {
     47         StringBuilder sb = new StringBuilder();
     48         for (int i=0; i<100; i++) {
     49             sb.append((char)i);
     50         }
     51 
     52         String result = ClassFileNameHandler.shortenPathComponent(sb.toString(), 5);
     53         Assert.assertEquals(95, result.getBytes(UTF8).length);
     54         Assert.assertEquals(95, result.length());
     55     }
     56 
     57     @Test
     58     public void test2ByteEncodings() {
     59         StringBuilder sb = new StringBuilder();
     60         for (int i=0x80; i<0x80+100; i++) {
     61             sb.append((char)i);
     62         }
     63 
     64         // remove a total of 3 2-byte characters, and then add back in the 1-byte '#'
     65         String result = ClassFileNameHandler.shortenPathComponent(sb.toString(), 4);
     66         Assert.assertEquals(200, sb.toString().getBytes(UTF8).length);
     67         Assert.assertEquals(195, result.getBytes(UTF8).length);
     68         Assert.assertEquals(98, result.length());
     69 
     70         // remove a total of 3 2-byte characters, and then add back in the 1-byte '#'
     71         result = ClassFileNameHandler.shortenPathComponent(sb.toString(), 5);
     72         Assert.assertEquals(200, sb.toString().getBytes(UTF8).length);
     73         Assert.assertEquals(195, result.getBytes(UTF8).length);
     74         Assert.assertEquals(98, result.length());
     75     }
     76 
     77     @Test
     78     public void test3ByteEncodings() {
     79         StringBuilder sb = new StringBuilder();
     80         for (int i=0x800; i<0x800+100; i++) {
     81             sb.append((char)i);
     82         }
     83 
     84         // remove a total of 3 3-byte characters, and then add back in the 1-byte '#'
     85         String result = ClassFileNameHandler.shortenPathComponent(sb.toString(), 6);
     86         Assert.assertEquals(300, sb.toString().getBytes(UTF8).length);
     87         Assert.assertEquals(292, result.getBytes(UTF8).length);
     88         Assert.assertEquals(98, result.length());
     89 
     90         // remove a total of 3 3-byte characters, and then add back in the 1-byte '#'
     91         result = ClassFileNameHandler.shortenPathComponent(sb.toString(), 7);
     92         Assert.assertEquals(300, sb.toString().getBytes(UTF8).length);
     93         Assert.assertEquals(292, result.getBytes(UTF8).length);
     94         Assert.assertEquals(98, result.length());
     95     }
     96 
     97     @Test
     98     public void test4ByteEncodings() {
     99         StringBuilder sb = new StringBuilder();
    100         for (int i=0x10000; i<0x10000+100; i++) {
    101             sb.appendCodePoint(i);
    102         }
    103 
    104         // we remove 3 codepoints == 6 characters == 12 bytes, and then add back in the 1-byte '#'
    105         String result = ClassFileNameHandler.shortenPathComponent(sb.toString(), 8);
    106         Assert.assertEquals(400, sb.toString().getBytes(UTF8).length);
    107         Assert.assertEquals(389, result.getBytes(UTF8).length);
    108         Assert.assertEquals(195, result.length());
    109 
    110         // we remove 2 codepoints == 4 characters == 8 bytes, and then add back in the 1-byte '#'
    111         result = ClassFileNameHandler.shortenPathComponent(sb.toString(), 7);
    112         Assert.assertEquals(400, sb.toString().getBytes(UTF8).length);
    113         Assert.assertEquals(393, result.getBytes(UTF8).length);
    114         Assert.assertEquals(197, result.length());
    115     }
    116 
    117     @Test
    118     public void testMultipleLongNames() {
    119         String filenameFragment = Strings.repeat("a", 512);
    120 
    121         File tempDir = Files.createTempDir();
    122         ClassFileNameHandler handler = new ClassFileNameHandler(tempDir, ".smali");
    123 
    124         // put the differentiating character in the middle, where it will get stripped out by the filename shortening
    125         // logic
    126         File file1 = handler.getUniqueFilenameForClass("La/a/" + filenameFragment  + "1" + filenameFragment + ";");
    127         checkFilename(tempDir, file1, "a", "a", Strings.repeat("a", 124) + "#" + Strings.repeat("a", 118) + ".smali");
    128 
    129         File file2 = handler.getUniqueFilenameForClass("La/a/" + filenameFragment + "2" + filenameFragment + ";");
    130         checkFilename(tempDir, file2, "a", "a", Strings.repeat("a", 124) + "#" + Strings.repeat("a", 118) + ".1.smali");
    131 
    132         Assert.assertFalse(file1.getAbsolutePath().equals(file2.getAbsolutePath()));
    133     }
    134 
    135     @Test
    136     public void testBasicFunctionality() {
    137         File tempDir = Files.createTempDir();
    138         ClassFileNameHandler handler = new ClassFileNameHandler(tempDir, ".smali");
    139 
    140         File file = handler.getUniqueFilenameForClass("La/b/c/d;");
    141         checkFilename(tempDir, file, "a", "b", "c", "d.smali");
    142 
    143         file = handler.getUniqueFilenameForClass("La/b/c/e;");
    144         checkFilename(tempDir, file, "a", "b", "c", "e.smali");
    145 
    146         file = handler.getUniqueFilenameForClass("La/b/d/d;");
    147         checkFilename(tempDir, file, "a", "b", "d", "d.smali");
    148 
    149         file = handler.getUniqueFilenameForClass("La/b;");
    150         checkFilename(tempDir, file, "a", "b.smali");
    151 
    152         file = handler.getUniqueFilenameForClass("Lb;");
    153         checkFilename(tempDir, file, "b.smali");
    154     }
    155 
    156     @Test
    157     public void testCaseInsensitiveFilesystem() {
    158         File tempDir = Files.createTempDir();
    159         ClassFileNameHandler handler = new ClassFileNameHandler(tempDir, ".smali", false, false);
    160 
    161         File file = handler.getUniqueFilenameForClass("La/b/c;");
    162         checkFilename(tempDir, file, "a", "b", "c.smali");
    163 
    164         file = handler.getUniqueFilenameForClass("La/b/C;");
    165         checkFilename(tempDir, file, "a", "b", "C.1.smali");
    166 
    167         file = handler.getUniqueFilenameForClass("La/B/c;");
    168         checkFilename(tempDir, file, "a", "B.1", "c.smali");
    169     }
    170 
    171     @Test
    172     public void testCaseSensitiveFilesystem() {
    173         File tempDir = Files.createTempDir();
    174         ClassFileNameHandler handler = new ClassFileNameHandler(tempDir, ".smali", true, false);
    175 
    176         File file = handler.getUniqueFilenameForClass("La/b/c;");
    177         checkFilename(tempDir, file, "a", "b", "c.smali");
    178 
    179         file = handler.getUniqueFilenameForClass("La/b/C;");
    180         checkFilename(tempDir, file, "a", "b", "C.smali");
    181 
    182         file = handler.getUniqueFilenameForClass("La/B/c;");
    183         checkFilename(tempDir, file, "a", "B", "c.smali");
    184     }
    185 
    186     @Test
    187     public void testWindowsReservedFilenames() {
    188         File tempDir = Files.createTempDir();
    189         ClassFileNameHandler handler = new ClassFileNameHandler(tempDir, ".smali", false, true);
    190 
    191         File file = handler.getUniqueFilenameForClass("La/con/c;");
    192         checkFilename(tempDir, file, "a", "con#", "c.smali");
    193 
    194         file = handler.getUniqueFilenameForClass("La/Con/c;");
    195         checkFilename(tempDir, file, "a", "Con#.1", "c.smali");
    196 
    197         file = handler.getUniqueFilenameForClass("La/b/PRN;");
    198         checkFilename(tempDir, file, "a", "b", "PRN#.smali");
    199 
    200         file = handler.getUniqueFilenameForClass("La/b/prN;");
    201         checkFilename(tempDir, file, "a", "b", "prN#.1.smali");
    202 
    203         file = handler.getUniqueFilenameForClass("La/b/com0;");
    204         checkFilename(tempDir, file, "a", "b", "com0.smali");
    205 
    206         for (String reservedName: new String[] {"con", "prn", "aux", "nul", "com1", "com9", "lpt1", "lpt9"}) {
    207             file = handler.getUniqueFilenameForClass("L" + reservedName + ";");
    208             checkFilename(tempDir, file, reservedName +"#.smali");
    209         }
    210     }
    211 
    212     @Test
    213     public void testIgnoringWindowsReservedFilenames() {
    214         File tempDir = Files.createTempDir();
    215         ClassFileNameHandler handler = new ClassFileNameHandler(tempDir, ".smali", true, false);
    216 
    217         File file = handler.getUniqueFilenameForClass("La/con/c;");
    218         checkFilename(tempDir, file, "a", "con", "c.smali");
    219 
    220         file = handler.getUniqueFilenameForClass("La/Con/c;");
    221         checkFilename(tempDir, file, "a", "Con", "c.smali");
    222 
    223         file = handler.getUniqueFilenameForClass("La/b/PRN;");
    224         checkFilename(tempDir, file, "a", "b", "PRN.smali");
    225 
    226         file = handler.getUniqueFilenameForClass("La/b/prN;");
    227         checkFilename(tempDir, file, "a", "b", "prN.smali");
    228 
    229         file = handler.getUniqueFilenameForClass("La/b/com0;");
    230         checkFilename(tempDir, file, "a", "b", "com0.smali");
    231 
    232         for (String reservedName: new String[] {"con", "prn", "aux", "nul", "com1", "com9", "lpt1", "lpt9"}) {
    233             file = handler.getUniqueFilenameForClass("L" + reservedName + ";");
    234             checkFilename(tempDir, file, reservedName +".smali");
    235         }
    236     }
    237 
    238     private void checkFilename(File base, File file, String... elements) {
    239         for (int i=elements.length-1; i>=0; i--) {
    240             Assert.assertEquals(elements[i], file.getName());
    241             file = file.getParentFile();
    242         }
    243         Assert.assertEquals(base.getAbsolutePath(), file.getAbsolutePath());
    244     }
    245 }
    246