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