Home | History | Annotate | Download | only in smali
      1 /*
      2  * Copyright 2016, 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.smali;import org.antlr.runtime.ANTLRInputStream;
     33 import org.antlr.runtime.CommonToken;
     34 import org.antlr.runtime.CommonTokenStream;
     35 import org.antlr.runtime.RecognitionException;
     36 import org.junit.Assert;
     37 import org.junit.Test;
     38 
     39 import java.io.File;
     40 import java.io.IOException;
     41 import java.io.InputStream;
     42 import java.io.InputStreamReader;
     43 import java.util.HashMap;
     44 import java.util.List;
     45 
     46 import static org.jf.smali.expectedTokensTestGrammarParser.ExpectedToken;
     47 
     48 public class LexerTest {
     49     private static final HashMap<String, Integer> tokenTypesByName;
     50 
     51     static {
     52         tokenTypesByName = new HashMap<String, Integer>();
     53 
     54         for (int i=0; i<smaliParser.tokenNames.length; i++) {
     55             tokenTypesByName.put(smaliParser.tokenNames[i], i);
     56         }
     57     }
     58 
     59     @Test
     60     public void DirectiveTest() {
     61         runTest("DirectiveTest");
     62     }
     63 
     64     @Test
     65     public void ByteLiteralTest() {
     66         runTest("ByteLiteralTest");
     67     }
     68 
     69     @Test
     70     public void ShortLiteralTest() {
     71         runTest("ShortLiteralTest");
     72     }
     73 
     74     @Test
     75     public void IntegerLiteralTest() {
     76         runTest("IntegerLiteralTest");
     77     }
     78 
     79     @Test
     80     public void LongLiteralTest() {
     81         runTest("LongLiteralTest");
     82     }
     83 
     84     @Test
     85     public void FloatLiteralTest() {
     86         runTest("FloatLiteralTest");
     87     }
     88 
     89     @Test
     90     public void CharLiteralTest() {
     91         runTest("CharLiteralTest");
     92     }
     93 
     94     @Test
     95     public void StringLiteralTest() {
     96         runTest("StringLiteralTest");
     97     }
     98 
     99     @Test
    100     public void MiscTest() {
    101         runTest("MiscTest");
    102     }
    103 
    104     @Test
    105     public void CommentTest() {
    106         runTest("CommentTest", false);
    107     }
    108 
    109     @Test
    110     public void InstructionTest() {
    111         runTest("InstructionTest", true);
    112     }
    113 
    114     @Test
    115     public void TypeAndIdentifierTest() {
    116         runTest("TypeAndIdentifierTest");
    117     }
    118 
    119     @Test
    120     public void SymbolTest() {
    121         runTest("SymbolTest", false);
    122     }
    123 
    124     @Test
    125     public void RealSmaliFileTest() {
    126         runTest("RealSmaliFileTest", true);
    127     }
    128 
    129     public void runTest(String test) {
    130         runTest(test, true);
    131     }
    132 
    133     public void runTest(String test, boolean discardHiddenTokens) {
    134         String smaliFile = String.format("LexerTest%s%s.smali", File.separatorChar, test);
    135         String tokensFile = String.format("LexerTest%s%s.tokens", File.separatorChar, test);
    136 
    137         org.jf.smali.expectedTokensTestGrammarLexer expectedTokensLexer = null;
    138         try {
    139             expectedTokensLexer = new org.jf.smali.expectedTokensTestGrammarLexer(new ANTLRInputStream(
    140                     LexerTest.class.getClassLoader().getResourceAsStream(tokensFile)));
    141         } catch (IOException ex) {
    142             throw new RuntimeException(ex);
    143         }
    144 
    145         CommonTokenStream expectedTokensStream = new CommonTokenStream(expectedTokensLexer);
    146 
    147         org.jf.smali.expectedTokensTestGrammarParser expectedTokensParser =
    148                 new org.jf.smali.expectedTokensTestGrammarParser(expectedTokensStream);
    149         try {
    150             expectedTokensParser.top();
    151         } catch (RecognitionException ex) {
    152             throw new RuntimeException(ex);
    153         }
    154 
    155         List<ExpectedToken> expectedTokens = expectedTokensParser.getExpectedTokens();
    156 
    157         InputStream smaliStream = LexerTest.class.getClassLoader().getResourceAsStream(smaliFile);
    158         if (smaliStream == null) {
    159             Assert.fail("Could not load " + smaliFile);
    160         }
    161         smaliFlexLexer lexer = new smaliFlexLexer(new InputStreamReader(smaliStream));
    162         lexer.setSourceFile(new File(test + ".smali"));
    163         lexer.setSuppressErrors(true);
    164 
    165         CommonTokenStream tokenStream = new CommonTokenStream(lexer);
    166         tokenStream.fill();
    167         List tokens = tokenStream.getTokens();
    168 
    169         int expectedTokenIndex = 0;
    170         CommonToken token;
    171         for (int i=0; i<tokens.size()-1; i++) {
    172             token = (CommonToken)tokens.get(i);
    173 
    174             if (discardHiddenTokens && token.getChannel() == smaliParser.HIDDEN) {
    175                 continue;
    176             }
    177 
    178             if (expectedTokenIndex >= expectedTokens.size()) {
    179                 Assert.fail("Too many tokens");
    180             }
    181 
    182             if (token.getType() == smaliParser.INVALID_TOKEN) {
    183                 Assert.assertTrue("Encountered an INVALID_TOKEN not on the error channel",
    184                         token.getChannel() == smaliParser.ERROR_CHANNEL);
    185             }
    186 
    187             ExpectedToken expectedToken = expectedTokens.get(expectedTokenIndex++);
    188             if (!tokenTypesByName.containsKey(expectedToken.tokenName)) {
    189                 Assert.fail("Unknown token: " + expectedToken.tokenName);
    190             }
    191             int expectedTokenType = tokenTypesByName.get(expectedToken.tokenName);
    192 
    193             if (token.getType() != expectedTokenType) {
    194                 Assert.fail(String.format("Invalid token at index %d. Expecting %s, got %s(%s)",
    195                         expectedTokenIndex-1, expectedToken.tokenName, getTokenName(token.getType()), token.getText()));
    196             }
    197 
    198             if (expectedToken.tokenText != null) {
    199                 if (!expectedToken.tokenText.equals(token.getText())) {
    200                     Assert.fail(
    201                             String.format("Invalid token text at index %d. Expecting text \"%s\", got \"%s\"",
    202                                     expectedTokenIndex - 1, expectedToken.tokenText, token.getText()));
    203                 }
    204             }
    205         }
    206 
    207         if (expectedTokenIndex < expectedTokens.size()) {
    208             Assert.fail(String.format("Not enough tokens. Expecting %d tokens, but got %d", expectedTokens.size(),
    209                     expectedTokenIndex));
    210         }
    211     }
    212 
    213 
    214 
    215     private static String getTokenName(int tokenType) {
    216         return smaliParser.tokenNames[tokenType];
    217     }
    218 }
    219