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