1 /* 2 * [The "BSD licence"] 3 * Copyright (c) 2010 Ben Gruver 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 import org.antlr.runtime.ANTLRInputStream; 30 import org.antlr.runtime.CommonToken; 31 import org.antlr.runtime.CommonTokenStream; 32 import org.antlr.runtime.RecognitionException; 33 import org.jf.dexlib.Util.Utf8Utils; 34 import org.jf.smali.*; 35 import static org.jf.smali.expectedTokensTestGrammarParser.ExpectedToken; 36 import org.junit.Assert; 37 import org.junit.Test; 38 39 import java.io.*; 40 import java.util.HashMap; 41 import java.util.List; 42 43 public class LexerTest { 44 private static final HashMap<String, Integer> tokenTypesByName; 45 46 static { 47 tokenTypesByName = new HashMap<String, Integer>(); 48 49 for (int i=0; i<smaliParser.tokenNames.length; i++) { 50 tokenTypesByName.put(smaliParser.tokenNames[i], i); 51 } 52 } 53 54 @Test 55 public void DirectiveTest() { 56 runTest("DirectiveTest"); 57 } 58 59 @Test 60 public void ByteLiteralTest() { 61 runTest("ByteLiteralTest"); 62 } 63 64 @Test 65 public void ShortLiteralTest() { 66 runTest("ShortLiteralTest"); 67 } 68 69 @Test 70 public void IntegerLiteralTest() { 71 runTest("IntegerLiteralTest"); 72 } 73 74 @Test 75 public void LongLiteralTest() { 76 runTest("LongLiteralTest"); 77 } 78 79 @Test 80 public void FloatLiteralTest() { 81 runTest("FloatLiteralTest"); 82 } 83 84 @Test 85 public void CharLiteralTest() { 86 runTest("CharLiteralTest"); 87 } 88 89 @Test 90 public void StringLiteralTest() { 91 runTest("StringLiteralTest"); 92 } 93 94 @Test 95 public void MiscTest() { 96 runTest("MiscTest"); 97 } 98 99 @Test 100 public void CommentTest() { 101 runTest("CommentTest", false); 102 } 103 104 @Test 105 public void InstructionTest() { 106 runTest("InstructionTest", true); 107 } 108 109 @Test 110 public void TypeAndIdentifierTest() { 111 runTest("TypeAndIdentifierTest"); 112 } 113 114 @Test 115 public void SymbolTest() { 116 runTest("SymbolTest", false); 117 } 118 119 @Test 120 public void RealSmaliFileTest() { 121 runTest("RealSmaliFileTest", true); 122 } 123 124 public void runTest(String test) { 125 runTest(test, true); 126 } 127 128 public void runTest(String test, boolean discardHiddenTokens) { 129 String smaliFile = String.format("LexerTest%s%s.smali", File.separatorChar, test); 130 String tokensFile = String.format("LexerTest%s%s.tokens", File.separatorChar, test); 131 132 expectedTokensTestGrammarLexer expectedTokensLexer = null; 133 try { 134 expectedTokensLexer = new expectedTokensTestGrammarLexer(new ANTLRInputStream( 135 LexerTest.class.getClassLoader().getResourceAsStream(tokensFile))); 136 } catch (IOException ex) { 137 throw new RuntimeException(ex); 138 } 139 140 CommonTokenStream expectedTokensStream = new CommonTokenStream(expectedTokensLexer); 141 142 expectedTokensTestGrammarParser expectedTokensParser = 143 new expectedTokensTestGrammarParser(expectedTokensStream); 144 try { 145 expectedTokensParser.top(); 146 } catch (RecognitionException ex) { 147 throw new RuntimeException(ex); 148 } 149 150 List<ExpectedToken> expectedTokens = expectedTokensParser.getExpectedTokens(); 151 152 InputStream smaliStream = LexerTest.class.getClassLoader().getResourceAsStream(smaliFile); 153 if (smaliStream == null) { 154 Assert.fail("Could not load " + smaliFile); 155 } 156 smaliFlexLexer lexer = new smaliFlexLexer(smaliStream); 157 lexer.setSourceFile(new File(test + ".smali")); 158 lexer.setSuppressErrors(true); 159 160 CommonTokenStream tokenStream = new CommonTokenStream(lexer); 161 List tokens = tokenStream.getTokens(); 162 163 int expectedTokenIndex = 0; 164 CommonToken token; 165 for (int i=0; i<tokens.size(); i++) { 166 token = (CommonToken)tokens.get(i); 167 168 if (discardHiddenTokens && token.getChannel() == smaliParser.HIDDEN) { 169 continue; 170 } 171 172 if (expectedTokenIndex >= expectedTokens.size()) { 173 Assert.fail("Too many tokens"); 174 } 175 176 if (token.getType() == smaliParser.INVALID_TOKEN) { 177 Assert.assertTrue("Encountered an INVALID_TOKEN not on the error channel", 178 token.getChannel() == smaliParser.ERROR_CHANNEL); 179 } 180 181 ExpectedToken expectedToken = expectedTokens.get(expectedTokenIndex++); 182 if (!tokenTypesByName.containsKey(expectedToken.tokenName)) { 183 Assert.fail("Unknown token: " + expectedToken.tokenName); 184 } 185 int expectedTokenType = tokenTypesByName.get(expectedToken.tokenName); 186 187 if (token.getType() != expectedTokenType) { 188 Assert.fail(String.format("Invalid token at index %d. Expecting %s, got %s(%s)", 189 expectedTokenIndex-1, expectedToken.tokenName, getTokenName(token.getType()), token.getText())); 190 } 191 192 if (expectedToken.tokenText != null) { 193 if (!expectedToken.tokenText.equals(token.getText())) { 194 Assert.fail( 195 String.format("Invalid token text at index %d. Expecting text \"%s\", got \"%s\"", 196 expectedTokenIndex - 1, expectedToken.tokenText, token.getText())); 197 } 198 } 199 } 200 201 if (expectedTokenIndex < expectedTokens.size()) { 202 Assert.fail(String.format("Not enough tokens. Expecting %d tokens, but got %d", expectedTokens.size(), 203 expectedTokenIndex)); 204 } 205 } 206 207 208 209 private static String getTokenName(int tokenType) { 210 return smaliParser.tokenNames[tokenType]; 211 } 212 } 213