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