Home | History | Annotate | Download | only in databinding
      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.BindingExpressionLexer;
     19 import android.databinding.parser.BindingExpressionParser;
     20 import android.databinding.parser.BindingExpressionParser.AndOrOpContext;
     21 import android.databinding.parser.BindingExpressionParser.BinaryOpContext;
     22 import android.databinding.parser.BindingExpressionParser.BindingSyntaxContext;
     23 import android.databinding.parser.BindingExpressionParser.BitShiftOpContext;
     24 import android.databinding.parser.BindingExpressionParser.ComparisonOpContext;
     25 import android.databinding.parser.BindingExpressionParser.DefaultsContext;
     26 import android.databinding.parser.BindingExpressionParser.DotOpContext;
     27 import android.databinding.parser.BindingExpressionParser.ExpressionContext;
     28 import android.databinding.parser.BindingExpressionParser.GroupingContext;
     29 import android.databinding.parser.BindingExpressionParser.LiteralContext;
     30 import android.databinding.parser.BindingExpressionParser.MathOpContext;
     31 import android.databinding.parser.BindingExpressionParser.PrimaryContext;
     32 import android.databinding.parser.BindingExpressionParser.PrimitiveTypeContext;
     33 import android.databinding.parser.BindingExpressionParser.QuestionQuestionOpContext;
     34 import android.databinding.parser.BindingExpressionParser.ResourceContext;
     35 import android.databinding.parser.BindingExpressionParser.StringLiteralContext;
     36 import android.databinding.parser.BindingExpressionParser.TernaryOpContext;
     37 import android.databinding.parser.BindingExpressionParser.UnaryOpContext;
     38 
     39 import org.antlr.v4.runtime.ANTLRInputStream;
     40 import org.antlr.v4.runtime.CommonTokenStream;
     41 import org.antlr.v4.runtime.Token;
     42 import org.antlr.v4.runtime.tree.TerminalNode;
     43 import org.junit.Test;
     44 
     45 import java.io.StringReader;
     46 
     47 import static org.junit.Assert.assertEquals;
     48 import static org.junit.Assert.assertNotNull;
     49 import static org.junit.Assert.assertNull;
     50 import static org.junit.Assert.assertTrue;
     51 
     52 public 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 }