• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.databinding;
17 
18 import android.databinding.parser.BindingExpressionBaseVisitor;
19 import android.databinding.parser.BindingExpressionLexer;
20 import android.databinding.parser.BindingExpressionParser;
21 import android.databinding.parser.BindingExpressionParser.AndOrOpContext;
22 import android.databinding.parser.BindingExpressionParser.BinaryOpContext;
23 import android.databinding.parser.BindingExpressionParser.BindingSyntaxContext;
24 import android.databinding.parser.BindingExpressionParser.BitShiftOpContext;
25 import android.databinding.parser.BindingExpressionParser.ComparisonOpContext;
26 import android.databinding.parser.BindingExpressionParser.DefaultsContext;
27 import android.databinding.parser.BindingExpressionParser.DotOpContext;
28 import android.databinding.parser.BindingExpressionParser.ExpressionContext;
29 import android.databinding.parser.BindingExpressionParser.GroupingContext;
30 import android.databinding.parser.BindingExpressionParser.LiteralContext;
31 import android.databinding.parser.BindingExpressionParser.MathOpContext;
32 import android.databinding.parser.BindingExpressionParser.PrimaryContext;
33 import android.databinding.parser.BindingExpressionParser.PrimitiveTypeContext;
34 import android.databinding.parser.BindingExpressionParser.QuestionQuestionOpContext;
35 import android.databinding.parser.BindingExpressionParser.ResourceContext;
36 import android.databinding.parser.BindingExpressionParser.StringLiteralContext;
37 import android.databinding.parser.BindingExpressionParser.TernaryOpContext;
38 import android.databinding.parser.BindingExpressionParser.UnaryOpContext;
39 
40 import org.antlr.v4.runtime.ANTLRInputStream;
41 import org.antlr.v4.runtime.CommonTokenStream;
42 import org.antlr.v4.runtime.Token;
43 import org.antlr.v4.runtime.misc.NotNull;
44 import org.antlr.v4.runtime.tree.TerminalNode;
45 import org.junit.Test;
46 
47 import java.io.StringReader;
48 
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.assertNotNull;
51 import static org.junit.Assert.assertNull;
52 import static org.junit.Assert.assertTrue;
53 
54 public class BindingExpressionParserTest {
55 
56     @Test
testSingleQuoteStringLiteral()57     public void testSingleQuoteStringLiteral() throws Exception {
58         String expr = "`test`";
59         LiteralContext literal = parseLiteral(expr);
60         assertNotNull(literal);
61         StringLiteralContext stringLiteral = literal.stringLiteral();
62         assertNotNull(stringLiteral);
63         TerminalNode singleQuote = stringLiteral.SingleQuoteString();
64         Token token = singleQuote.getSymbol();
65         assertEquals("`test`", token.getText());
66     }
67 
68     @Test
testDoubleQuoteStringLiteral()69     public void testDoubleQuoteStringLiteral() throws Exception {
70         String expr = "\"test\"";
71 
72         LiteralContext literal = parseLiteral(expr);
73         StringLiteralContext stringLiteral = literal.stringLiteral();
74         TerminalNode singleQuote = stringLiteral.DoubleQuoteString();
75         Token token = singleQuote.getSymbol();
76         assertEquals("\"test\"", token.getText());
77     }
78 
79     @Test
testSingleQuoteEscapeStringLiteral()80     public void testSingleQuoteEscapeStringLiteral() throws Exception {
81         String expr = "`\"t\\`est\"`";
82         LiteralContext literal = parseLiteral(expr);
83         StringLiteralContext stringLiteral = literal.stringLiteral();
84         TerminalNode singleQuote = stringLiteral.SingleQuoteString();
85         Token token = singleQuote.getSymbol();
86         assertEquals("`\"t\\`est\"`", token.getText());
87     }
88 
89     @Test
testCharLiteral()90     public void testCharLiteral() throws Exception {
91         LiteralContext literal = parseLiteral("'c'");
92         assertEquals("'c'", literal.getText());
93         literal = parseLiteral("'\\u0054'");
94         assertEquals("'\\u0054'", literal.getText());
95         literal = parseLiteral("'\\''");
96         assertEquals("'\\''", literal.getText());
97     }
98 
99     @Test
testIntLiterals()100     public void testIntLiterals() throws Exception {
101         compareIntLiteral("123");
102         compareIntLiteral("123l");
103         compareIntLiteral("1_2_3l");
104         compareIntLiteral("123L");
105         compareIntLiteral("0xdeadbeef");
106         compareIntLiteral("0xdeadbeefl");
107         compareIntLiteral("0Xdeadbeef");
108         compareIntLiteral("0xdead_beefl");
109         compareIntLiteral("0xdead_beefL");
110         compareIntLiteral("01234567");
111         compareIntLiteral("01234567L");
112         compareIntLiteral("01234567l");
113         compareIntLiteral("0123_45_67l");
114         compareIntLiteral("0b0101");
115         compareIntLiteral("0b0101_0101");
116         compareIntLiteral("0B0101_0101");
117         compareIntLiteral("0B0101_0101L");
118         compareIntLiteral("0B0101_0101l");
119     }
120 
121     @Test
testFloatLiterals()122     public void testFloatLiterals() throws Exception {
123         compareFloatLiteral("0.12345");
124         compareFloatLiteral("0.12345f");
125         compareFloatLiteral("0.12345F");
126         compareFloatLiteral("132450.12345F");
127         compareFloatLiteral("132450.12345");
128         compareFloatLiteral("132450e123");
129         compareFloatLiteral("132450.4e123");
130     }
131 
132     @Test
testBoolLiterals()133     public void testBoolLiterals() throws Exception {
134         compareBoolLiteral("true");
135         compareBoolLiteral("false");
136     }
137 
138     @Test
testNullLiteral()139     public void testNullLiteral() throws Exception {
140         LiteralContext literal = parseLiteral("null");
141         String token = literal.getText();
142         assertEquals("null", token);
143     }
144 
145     @Test
testPrimitiveClassExtraction()146     public void testPrimitiveClassExtraction() throws Exception {
147         PrimaryContext primary = parsePrimary("int.class");
148         PrimitiveTypeContext type = primary.classExtraction().type().primitiveType();
149         assertEquals("int", type.getText());
150     }
151 
152     @Test
testIdentifier()153     public void testIdentifier() throws Exception {
154         PrimaryContext primary = parsePrimary("abcdEfg");
155         assertEquals("abcdEfg", primary.identifier().getText());
156     }
157 
158     @Test
testUnaryOperators()159     public void testUnaryOperators() throws Exception {
160         compareUnaryOperators("+");
161         compareUnaryOperators("-");
162         compareUnaryOperators("!");
163         compareUnaryOperators("~");
164     }
165 
166     @Test
testMathOperators()167     public void testMathOperators() throws Exception {
168         compareMathOperators("+");
169         compareMathOperators("-");
170         compareMathOperators("*");
171         compareMathOperators("/");
172         compareMathOperators("%");
173     }
174 
175     @Test
testBitShiftOperators()176     public void testBitShiftOperators() throws Exception {
177         compareBitShiftOperators(">>>");
178         compareBitShiftOperators("<<");
179         compareBitShiftOperators(">>");
180     }
181 
182     @Test
testComparisonShiftOperators()183     public void testComparisonShiftOperators() throws Exception {
184         compareComparisonOperators("<");
185         compareComparisonOperators(">");
186         compareComparisonOperators("<=");
187         compareComparisonOperators(">=");
188         compareComparisonOperators("==");
189         compareComparisonOperators("!=");
190     }
191 
192     @Test
testAndOrOperators()193     public void testAndOrOperators() throws Exception {
194         compareAndOrOperators("&&");
195         compareAndOrOperators("||");
196     }
197 
198     @Test
testBinaryOperators()199     public void testBinaryOperators() throws Exception {
200         compareBinaryOperators("&");
201         compareBinaryOperators("|");
202         compareBinaryOperators("^");
203     }
204 
205     @Test
testTernaryOperator()206     public void testTernaryOperator() throws Exception {
207         TernaryOpContext expression = parseExpression("true ? 1 : 0");
208         assertEquals(5, expression.getChildCount());
209         assertEquals("true",
210                 ((PrimaryContext) expression.left).literal().javaLiteral().getText());
211         assertEquals("?", expression.op.getText());
212         assertEquals("1",
213                 ((PrimaryContext) expression.iftrue).literal().javaLiteral().getText());
214         assertEquals(":", expression.getChild(3).getText());
215         assertEquals("0", ((PrimaryContext) expression.iffalse).literal().javaLiteral().getText());
216     }
217 
218     @Test
testDot()219     public void testDot() throws Exception {
220         DotOpContext expression = parseExpression("one.two.three");
221         assertEquals(3, expression.getChildCount());
222         assertEquals("three", expression.Identifier().getText());
223         assertEquals(".", expression.getChild(1).getText());
224         DotOpContext left = (DotOpContext) expression.expression();
225         assertEquals("two", left.Identifier().getText());
226         assertEquals(".", left.getChild(1).getText());
227         assertEquals("one", ((PrimaryContext) left.expression()).identifier().getText());
228     }
229 
230     @Test
testQuestionQuestion()231     public void testQuestionQuestion() throws Exception {
232         QuestionQuestionOpContext expression = parseExpression("one ?? two");
233         assertEquals(3, expression.getChildCount());
234         assertEquals("one", ((PrimaryContext) expression.left).identifier().getText());
235         assertEquals("two", ((PrimaryContext) expression.right).identifier().getText());
236         assertEquals("??", expression.op.getText());
237     }
238 
239     @Test
testResourceReference()240     public void testResourceReference() throws Exception {
241         compareResource("@id/foo_bar");
242         compareResource("@transition/foo_bar");
243         compareResource("@anim/foo_bar");
244         compareResource("@animator/foo_bar");
245         compareResource("@android:id/foo_bar");
246         compareResource("@app:id/foo_bar");
247     }
248 
249     @Test
testDefaults()250     public void testDefaults() throws Exception {
251         BindingSyntaxContext syntax = parseExpressionString("foo.bar, default = @id/foo_bar");
252         BindingExpressionParser.DefaultsContext defaults = syntax
253                 .accept(new BindingExpressionBaseVisitor<DefaultsContext>() {
254                     @Override
255                     public BindingExpressionParser.DefaultsContext visitDefaults(
256                             @NotNull BindingExpressionParser.DefaultsContext ctx) {
257                         return ctx;
258                     }
259                 });
260         assertEquals("@id/foo_bar", defaults.constantValue().ResourceReference().getText());
261     }
262 
263     @Test
testParentheses()264     public void testParentheses() throws Exception {
265         GroupingContext grouping = parseExpression("(1234)");
266         assertEquals("1234", grouping.expression().getText());
267     }
268 
269     // ---------------------- Helpers --------------------
270 
compareResource(String value)271     private void compareResource(String value) throws Exception {
272         ResourceContext resourceContext = parseExpression(value);
273         assertEquals(value, resourceContext.getText());
274     }
275 
compareUnaryOperators(String op)276     private void compareUnaryOperators(String op) throws Exception {
277         UnaryOpContext expression = parseExpression(op + " 2");
278         assertEquals(2, expression.getChildCount());
279         assertEquals(op, expression.op.getText());
280         assertEquals("2",
281                 ((PrimaryContext) expression.expression()).literal().javaLiteral()
282                         .getText());
283     }
284 
compareBinaryOperators(String op)285     private void compareBinaryOperators(String op) throws Exception {
286         BinaryOpContext expression = parseExpression("1 " + op + " 2");
287         assertEquals(3, expression.getChildCount());
288         assertTrue(expression.left instanceof ExpressionContext);
289         String one = ((PrimaryContext) expression.left).literal().javaLiteral().getText();
290         assertEquals("1", one);
291         assertEquals(op, expression.op.getText());
292         assertTrue(expression.right instanceof ExpressionContext);
293         String two = ((PrimaryContext) expression.right).literal().javaLiteral().getText();
294         assertEquals("2", two);
295     }
296 
compareMathOperators(String op)297     private void compareMathOperators(String op) throws Exception {
298         MathOpContext expression = parseExpression("1 " + op + " 2");
299         assertEquals(3, expression.getChildCount());
300         assertTrue(expression.left instanceof ExpressionContext);
301         String one = ((PrimaryContext) expression.left).literal().javaLiteral().getText();
302         assertEquals("1", one);
303         assertEquals(op, expression.op.getText());
304         assertTrue(expression.right instanceof ExpressionContext);
305         String two = ((PrimaryContext) expression.right).literal().javaLiteral().getText();
306         assertEquals("2", two);
307     }
308 
compareBitShiftOperators(String op)309     private void compareBitShiftOperators(String op) throws Exception {
310         BitShiftOpContext expression = parseExpression("1 " + op + " 2");
311         assertEquals(3, expression.getChildCount());
312         assertTrue(expression.left instanceof ExpressionContext);
313         String one = ((PrimaryContext) expression.left).literal().javaLiteral().getText();
314         assertEquals("1", one);
315         assertEquals(op, expression.op.getText());
316         assertTrue(expression.right instanceof ExpressionContext);
317         String two = ((PrimaryContext) expression.right).literal().javaLiteral().getText();
318         assertEquals("2", two);
319     }
320 
compareComparisonOperators(String op)321     private void compareComparisonOperators(String op) throws Exception {
322         ComparisonOpContext expression = parseExpression("1 " + op + " 2");
323         assertEquals(3, expression.getChildCount());
324         assertTrue(expression.left instanceof ExpressionContext);
325         String one = ((PrimaryContext) expression.left).literal().javaLiteral().getText();
326         assertEquals("1", one);
327         assertEquals(op, expression.op.getText());
328         assertTrue(expression.right instanceof ExpressionContext);
329         String two = ((PrimaryContext) expression.right).literal().javaLiteral().getText();
330         assertEquals("2", two);
331     }
332 
compareAndOrOperators(String op)333     private void compareAndOrOperators(String op) throws Exception {
334         AndOrOpContext expression = parseExpression("1 " + op + " 2");
335         assertEquals(3, expression.getChildCount());
336         assertTrue(expression.left instanceof ExpressionContext);
337         String one = ((PrimaryContext) expression.left).literal().javaLiteral().getText();
338         assertEquals("1", one);
339         assertEquals(op, expression.op.getText());
340         assertTrue(expression.right instanceof ExpressionContext);
341         String two = ((PrimaryContext) expression.right).literal().javaLiteral().getText();
342         assertEquals("2", two);
343     }
344 
compareIntLiteral(String constant)345     private void compareIntLiteral(String constant) throws Exception {
346         LiteralContext literal = parseLiteral(constant);
347         String token = literal.javaLiteral().getText();
348         assertEquals(constant, token);
349     }
350 
compareFloatLiteral(String constant)351     private void compareFloatLiteral(String constant) throws Exception {
352         LiteralContext literal = parseLiteral(constant);
353         String token = literal.javaLiteral().getText();
354         assertEquals(constant, token);
355     }
356 
compareBoolLiteral(String constant)357     private void compareBoolLiteral(String constant) throws Exception {
358         LiteralContext literal = parseLiteral(constant);
359         String token = literal.javaLiteral().getText();
360         assertEquals(constant, token);
361     }
362 
parse(String value)363     private BindingSyntaxContext parse(String value) throws Exception {
364         return parseExpressionString(value);
365     }
366 
parseExpression(String value)367     private <T extends ExpressionContext> T parseExpression(String value) throws Exception {
368         return (T) parse(value).accept(new BindingExpressionBaseVisitor<ExpressionContext>() {
369             @Override
370             public ExpressionContext visitRootExpr(
371                     @NotNull BindingExpressionParser.RootExprContext ctx) {
372                 return ctx.expression();
373             }
374         });
375     }
376 
377     private PrimaryContext parsePrimary(String value) throws Exception {
378         return parseExpression(value);
379     }
380 
381     private LiteralContext parseLiteral(String value) throws Exception {
382         return parsePrimary(value).literal();
383     }
384 
385     BindingExpressionParser.BindingSyntaxContext parseExpressionString(String s) throws Exception {
386         ANTLRInputStream input = new ANTLRInputStream(new StringReader(s));
387         BindingExpressionLexer lexer = new BindingExpressionLexer(input);
388         CommonTokenStream tokens = new CommonTokenStream(lexer);
389         BindingExpressionParser parser = new BindingExpressionParser(tokens);
390         return parser.bindingSyntax();
391     }
392 }