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}