blob: 5137b45c65f384b39b66fbbeee14f73d16efac26 [file] [log] [blame]
Ulf Adams89f012d2015-02-26 13:39:28 +00001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.syntax;
15
16import static com.google.common.truth.Truth.assertThat;
17import static com.google.common.truth.Truth.assertWithMessage;
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000018import static org.junit.Assert.assertEquals;
19import static org.junit.Assert.assertFalse;
20import static org.junit.Assert.assertTrue;
21import static org.junit.Assert.fail;
Ulf Adams89f012d2015-02-26 13:39:28 +000022
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +000023import com.google.common.collect.ImmutableList;
Ulf Adams89f012d2015-02-26 13:39:28 +000024import com.google.devtools.build.lib.events.Location;
25import com.google.devtools.build.lib.syntax.DictionaryLiteral.DictionaryEntryLiteral;
26
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000027import org.junit.Before;
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000028import org.junit.Test;
29import org.junit.runner.RunWith;
30import org.junit.runners.JUnit4;
31
Florian Weikert9d659ad2015-07-23 14:44:36 +000032import java.util.LinkedList;
Ulf Adams89f012d2015-02-26 13:39:28 +000033import java.util.List;
34
Ulf Adams89f012d2015-02-26 13:39:28 +000035/**
36 * Tests of parser behaviour.
Ulf Adams89f012d2015-02-26 13:39:28 +000037 */
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000038@RunWith(JUnit4.class)
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000039public class ParserTest extends EvaluationTestCase {
40
Francois-Rene Rideau5a94e592015-09-04 19:13:47 +000041 Environment buildEnvironment;
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000042
43 @Before
44 @Override
45 public void setUp() throws Exception {
46 super.setUp();
Francois-Rene Rideau5a94e592015-09-04 19:13:47 +000047 buildEnvironment = newBuildEnvironment();
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000048 }
49
50 private Parser.ParseResult parseFileWithComments(String... input) {
Francois-Rene Rideau5a94e592015-09-04 19:13:47 +000051 return buildEnvironment.parseFileWithComments(input);
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000052 }
53
Francois-Rene Rideau5a94e592015-09-04 19:13:47 +000054 /** Parses build code (not Skylark) */
55 @Override
56 protected List<Statement> parseFile(String... input) {
57 return buildEnvironment.parseFile(input);
58 }
59
60 /** Parses a build code (not Skylark) with PythonProcessing enabled */
61 private List<Statement> parseFileWithPython(String... input) {
62 return Parser.parseFile(
63 buildEnvironment.createLexer(input),
64 getEventHandler(),
65 Environment.EMPTY_PACKAGE_LOCATOR,
66 /*parsePython=*/true).statements;
67 }
68
69 /** Parses Skylark code */
70 private List<Statement> parseFileForSkylark(String... input) {
71 return env.parseFile(input);
72 }
Ulf Adams89f012d2015-02-26 13:39:28 +000073
74 private static String getText(String text, ASTNode node) {
75 return text.substring(node.getLocation().getStartOffset(),
76 node.getLocation().getEndOffset());
77 }
78
79 // helper func for testListLiterals:
80 private static int getIntElem(DictionaryEntryLiteral entry, boolean key) {
81 return ((IntegerLiteral) (key ? entry.getKey() : entry.getValue())).getValue();
82 }
83
84 // helper func for testListLiterals:
85 private static DictionaryEntryLiteral getElem(DictionaryLiteral list, int index) {
86 return list.getEntries().get(index);
87 }
88
89 // helper func for testListLiterals:
90 private static int getIntElem(ListLiteral list, int index) {
91 return ((IntegerLiteral) list.getElements().get(index)).getValue();
92 }
93
94 // helper func for testListLiterals:
95 private static Expression getElem(ListLiteral list, int index) {
96 return list.getElements().get(index);
97 }
98
99 // helper func for testing arguments:
100 private static Expression getArg(FuncallExpression f, int index) {
101 return f.getArguments().get(index).getValue();
102 }
103
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000104 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000105 public void testPrecedence1() throws Exception {
106 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000107 (BinaryOperatorExpression) parseExpression("'%sx' % 'foo' + 'bar'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000108
109 assertEquals(Operator.PLUS, e.getOperator());
110 }
111
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000112 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000113 public void testPrecedence2() throws Exception {
114 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000115 (BinaryOperatorExpression) parseExpression("('%sx' % 'foo') + 'bar'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000116 assertEquals(Operator.PLUS, e.getOperator());
117 }
118
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000119 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000120 public void testPrecedence3() throws Exception {
121 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000122 (BinaryOperatorExpression) parseExpression("'%sx' % ('foo' + 'bar')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000123 assertEquals(Operator.PERCENT, e.getOperator());
124 }
125
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000126 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000127 public void testPrecedence4() throws Exception {
128 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000129 (BinaryOperatorExpression) parseExpression("1 + - (2 - 3)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000130 assertEquals(Operator.PLUS, e.getOperator());
131 }
132
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000133 @Test
Laurent Le Brun7bda87e2015-08-24 15:13:53 +0000134 public void testPrecedence5() throws Exception {
135 BinaryOperatorExpression e =
136 (BinaryOperatorExpression) parseExpression("2 * x | y + 1");
137 assertEquals(Operator.PIPE, e.getOperator());
138 }
139
140 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000141 public void testUnaryMinusExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000142 FuncallExpression e = (FuncallExpression) parseExpression("-5");
143 FuncallExpression e2 = (FuncallExpression) parseExpression("- 5");
Ulf Adams89f012d2015-02-26 13:39:28 +0000144
145 assertEquals("-", e.getFunction().getName());
146 assertEquals("-", e2.getFunction().getName());
147
148 assertThat(e.getArguments()).hasSize(1);
149 assertEquals(1, e.getNumPositionalArguments());
150
151 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
152 assertEquals(5, (int) arg0.getValue());
153 }
154
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000155 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000156 public void testFuncallExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000157 FuncallExpression e = (FuncallExpression) parseExpression("foo(1, 2, bar=wiz)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000158
Florian Weikert6f864c32015-07-23 11:26:39 +0000159 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000160 assertEquals("foo", ident.getName());
161
162 assertThat(e.getArguments()).hasSize(3);
163 assertEquals(2, e.getNumPositionalArguments());
164
165 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
166 assertEquals(1, (int) arg0.getValue());
167
168 IntegerLiteral arg1 = (IntegerLiteral) e.getArguments().get(1).getValue();
169 assertEquals(2, (int) arg1.getValue());
170
171 Argument.Passed arg2 = e.getArguments().get(2);
172 assertEquals("bar", arg2.getName());
Florian Weikert6f864c32015-07-23 11:26:39 +0000173 Identifier arg2val = (Identifier) arg2.getValue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000174 assertEquals("wiz", arg2val.getName());
175 }
176
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000177 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000178 public void testMethCallExpr() throws Exception {
179 FuncallExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000180 (FuncallExpression) parseExpression("foo.foo(1, 2, bar=wiz)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000181
Florian Weikert6f864c32015-07-23 11:26:39 +0000182 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000183 assertEquals("foo", ident.getName());
184
185 assertThat(e.getArguments()).hasSize(3);
186 assertEquals(2, e.getNumPositionalArguments());
187
188 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
189 assertEquals(1, (int) arg0.getValue());
190
191 IntegerLiteral arg1 = (IntegerLiteral) e.getArguments().get(1).getValue();
192 assertEquals(2, (int) arg1.getValue());
193
194 Argument.Passed arg2 = e.getArguments().get(2);
195 assertEquals("bar", arg2.getName());
Florian Weikert6f864c32015-07-23 11:26:39 +0000196 Identifier arg2val = (Identifier) arg2.getValue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000197 assertEquals("wiz", arg2val.getName());
198 }
199
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000200 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000201 public void testChainedMethCallExpr() throws Exception {
202 FuncallExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000203 (FuncallExpression) parseExpression("foo.replace().split(1)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000204
Florian Weikert6f864c32015-07-23 11:26:39 +0000205 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000206 assertEquals("split", ident.getName());
207
208 assertThat(e.getArguments()).hasSize(1);
209 assertEquals(1, e.getNumPositionalArguments());
210
211 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
212 assertEquals(1, (int) arg0.getValue());
213 }
214
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000215 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000216 public void testPropRefExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000217 DotExpression e = (DotExpression) parseExpression("foo.foo");
Ulf Adams89f012d2015-02-26 13:39:28 +0000218
Florian Weikert6f864c32015-07-23 11:26:39 +0000219 Identifier ident = e.getField();
Ulf Adams89f012d2015-02-26 13:39:28 +0000220 assertEquals("foo", ident.getName());
221 }
222
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000223 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000224 public void testStringMethExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000225 FuncallExpression e = (FuncallExpression) parseExpression("'foo'.foo()");
Ulf Adams89f012d2015-02-26 13:39:28 +0000226
Florian Weikert6f864c32015-07-23 11:26:39 +0000227 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000228 assertEquals("foo", ident.getName());
229
230 assertThat(e.getArguments()).isEmpty();
231 }
232
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000233 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000234 public void testStringLiteralOptimizationValue() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000235 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000236 assertEquals("abcdef", l.value);
237 }
238
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000239 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000240 public void testStringLiteralOptimizationToString() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000241 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000242 assertEquals("'abcdef'", l.toString());
243 }
244
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000245 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000246 public void testStringLiteralOptimizationLocation() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000247 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000248 assertEquals(0, l.getLocation().getStartOffset());
249 assertEquals(13, l.getLocation().getEndOffset());
250 }
251
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000252 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000253 public void testStringLiteralOptimizationDifferentQuote() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000254 assertThat(parseExpression("'abc' + \"def\"")).isInstanceOf(BinaryOperatorExpression.class);
Ulf Adams89f012d2015-02-26 13:39:28 +0000255 }
256
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000257 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000258 public void testSubstring() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000259 FuncallExpression e = (FuncallExpression) parseExpression("'FOO.CC'[:].lower()[1:]");
Laurent Le Bruneeef30f2015-03-16 15:12:35 +0000260 assertEquals("$slice", e.getFunction().getName());
Ulf Adams89f012d2015-02-26 13:39:28 +0000261 assertThat(e.getArguments()).hasSize(2);
262
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000263 e = (FuncallExpression) parseExpression("'FOO.CC'.lower()[1:].startswith('oo')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000264 assertEquals("startswith", e.getFunction().getName());
265 assertThat(e.getArguments()).hasSize(1);
266
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000267 e = (FuncallExpression) parseExpression("'FOO.CC'[1:][:2]");
Laurent Le Bruneeef30f2015-03-16 15:12:35 +0000268 assertEquals("$slice", e.getFunction().getName());
Ulf Adams89f012d2015-02-26 13:39:28 +0000269 assertThat(e.getArguments()).hasSize(2);
270 }
271
272 private void assertLocation(int start, int end, Location location)
273 throws Exception {
274 int actualStart = location.getStartOffset();
275 int actualEnd = location.getEndOffset();
276
277 if (actualStart != start || actualEnd != end) {
278 fail("Expected location = [" + start + ", " + end + "), found ["
279 + actualStart + ", " + actualEnd + ")");
280 }
281 }
282
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000283 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000284 public void testErrorRecovery() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000285 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000286
Laurent Le Brun443aaae2015-04-21 19:49:49 +0000287 String expr = "f(1, [x for foo foo foo foo], 3)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000288 FuncallExpression e = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000289
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000290 assertContainsEvent("syntax error at 'foo'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000291
292 // Test that the actual parameters are: (1, $error$, 3):
293
Florian Weikert6f864c32015-07-23 11:26:39 +0000294 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000295 assertEquals("f", ident.getName());
296
297 assertThat(e.getArguments()).hasSize(3);
298 assertEquals(3, e.getNumPositionalArguments());
299
300 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
301 assertEquals(1, (int) arg0.getValue());
302
303 Argument.Passed arg1 = e.getArguments().get(1);
Florian Weikert6f864c32015-07-23 11:26:39 +0000304 Identifier arg1val = ((Identifier) arg1.getValue());
Ulf Adams89f012d2015-02-26 13:39:28 +0000305 assertEquals("$error$", arg1val.getName());
306
Laurent Le Brun443aaae2015-04-21 19:49:49 +0000307 assertLocation(5, 29, arg1val.getLocation());
308 assertEquals("[x for foo foo foo foo]", expr.substring(5, 28));
309 assertEquals(30, arg1val.getLocation().getEndLineAndColumn().getColumn());
Ulf Adams89f012d2015-02-26 13:39:28 +0000310
311 IntegerLiteral arg2 = (IntegerLiteral) e.getArguments().get(2).getValue();
312 assertEquals(3, (int) arg2.getValue());
313 }
314
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000315 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000316 public void testDoesntGetStuck() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000317 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000318
319 // Make sure the parser does not get stuck when trying
320 // to parse an expression containing a syntax error.
321 // This usually results in OutOfMemoryError because the
322 // parser keeps filling up the error log.
323 // We need to make sure that we will always advance
324 // in the token stream.
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000325 parseExpression("f(1, ], 3)");
326 parseExpression("f(1, ), 3)");
327 parseExpression("[ ) for v in 3)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000328
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000329 assertContainsEvent(""); // "" matches any;
Ulf Adams89f012d2015-02-26 13:39:28 +0000330 // i.e. there were some events
331 }
332
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000333 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000334 public void testSecondaryLocation() {
335 String expr = "f(1 % 2)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000336 FuncallExpression call = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000337 Argument.Passed arg = call.getArguments().get(0);
Francois-Rene Rideauc673a822015-03-02 19:52:39 +0000338 assertThat(arg.getLocation().getEndOffset()).isLessThan(call.getLocation().getEndOffset());
Ulf Adams89f012d2015-02-26 13:39:28 +0000339 }
340
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000341 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000342 public void testPrimaryLocation() {
343 String expr = "f(1 + 2)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000344 FuncallExpression call = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000345 Argument.Passed arg = call.getArguments().get(0);
Francois-Rene Rideauc673a822015-03-02 19:52:39 +0000346 assertThat(arg.getLocation().getEndOffset()).isLessThan(call.getLocation().getEndOffset());
Ulf Adams89f012d2015-02-26 13:39:28 +0000347 }
348
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000349 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000350 public void testAssignLocation() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000351 List<Statement> statements = parseFile("a = b;c = d\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000352 Statement statement = statements.get(0);
353 assertEquals(5, statement.getLocation().getEndOffset());
354 }
355
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000356 @Test
Laurent Le Brunc9041bf2015-03-23 15:34:12 +0000357 public void testAssignKeyword() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000358 setFailFast(false);
359 parseExpression("with = 4");
360 assertContainsEvent("keyword 'with' not supported");
361 assertContainsEvent("syntax error at 'with': expected expression");
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000362 }
363
364 @Test
Laurent Le Brunee991a12015-06-16 10:56:46 +0000365 public void testBreak() {
366 setFailFast(false);
367 parseExpression("break");
368 assertContainsEvent("syntax error at 'break': expected expression");
369 }
370
371 @Test
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000372 public void testTry() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000373 setFailFast(false);
374 parseExpression("try: 1 + 1");
375 assertContainsEvent("'try' not supported, all exceptions are fatal");
376 assertContainsEvent("syntax error at 'try': expected expression");
Laurent Le Brunc9041bf2015-03-23 15:34:12 +0000377 }
378
379 @Test
Laurent Le Brun56093892015-03-20 13:01:58 +0000380 public void testTupleAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000381 List<Statement> statements = parseFile("list[0] = 5; dict['key'] = value\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000382 assertThat(statements).hasSize(2);
Laurent Le Brun56093892015-03-20 13:01:58 +0000383 assertThat(statements.get(0)).isInstanceOf(AssignmentStatement.class);
384 assertThat(statements.get(1)).isInstanceOf(AssignmentStatement.class);
385 }
386
387 @Test
388 public void testAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000389 List<Statement> statements = parseFile("a, b = 5\n");
Laurent Le Brun56093892015-03-20 13:01:58 +0000390 assertThat(statements).hasSize(1);
391 assertThat(statements.get(0)).isInstanceOf(AssignmentStatement.class);
392 AssignmentStatement assign = (AssignmentStatement) statements.get(0);
393 assertThat(assign.getLValue().getExpression()).isInstanceOf(ListLiteral.class);
Ulf Adams89f012d2015-02-26 13:39:28 +0000394 }
395
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000396 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000397 public void testInvalidAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000398 setFailFast(false);
399 parseExpression("1 + (b = c)");
400 assertContainsEvent("syntax error");
401 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000402 }
403
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000404 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000405 public void testAugmentedAssign() throws Exception {
406 assertEquals("[x = x + 1\n]", parseFile("x += 1").toString());
407 }
408
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000409 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000410 public void testPrettyPrintFunctions() throws Exception {
411 assertEquals("[x[1:3]\n]", parseFile("x[1:3]").toString());
412 assertEquals("[str[42]\n]", parseFile("str[42]").toString());
Francois-Rene Rideau9e3cc2e2015-05-18 18:35:36 +0000413 assertEquals("[ctx.new_file('hello')\n]", parseFile("ctx.new_file('hello')").toString());
414 assertEquals("[new_file('hello')\n]", parseFile("new_file('hello')").toString());
Ulf Adams89f012d2015-02-26 13:39:28 +0000415 }
416
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000417 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000418 public void testFuncallLocation() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000419 List<Statement> statements = parseFile("a(b);c = d\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000420 Statement statement = statements.get(0);
421 assertEquals(4, statement.getLocation().getEndOffset());
422 }
423
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000424 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000425 public void testSpecialFuncallLocation() throws Exception {
426 List<Statement> statements = parseFile("-x\n");
427 assertLocation(0, 3, statements.get(0).getLocation());
428
429 statements = parseFile("arr[15]\n");
430 assertLocation(0, 8, statements.get(0).getLocation());
431
432 statements = parseFile("str[1:12]\n");
433 assertLocation(0, 10, statements.get(0).getLocation());
434 }
435
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000436 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000437 public void testListPositions() throws Exception {
438 String expr = "[0,f(1),2]";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000439 ListLiteral list = (ListLiteral) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000440 assertEquals("[0,f(1),2]", getText(expr, list));
441 assertEquals("0", getText(expr, getElem(list, 0)));
442 assertEquals("f(1)", getText(expr, getElem(list, 1)));
443 assertEquals("2", getText(expr, getElem(list, 2)));
444 }
445
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000446 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000447 public void testDictPositions() throws Exception {
448 String expr = "{1:2,2:f(1),3:4}";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000449 DictionaryLiteral list = (DictionaryLiteral) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000450 assertEquals("{1:2,2:f(1),3:4}", getText(expr, list));
451 assertEquals("1:2", getText(expr, getElem(list, 0)));
452 assertEquals("2:f(1)", getText(expr, getElem(list, 1)));
453 assertEquals("3:4", getText(expr, getElem(list, 2)));
454 }
455
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000456 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000457 public void testArgumentPositions() throws Exception {
458 String stmt = "f(0,g(1,2),2)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000459 FuncallExpression f = (FuncallExpression) parseExpression(stmt);
Ulf Adams89f012d2015-02-26 13:39:28 +0000460 assertEquals(stmt, getText(stmt, f));
461 assertEquals("0", getText(stmt, getArg(f, 0)));
462 assertEquals("g(1,2)", getText(stmt, getArg(f, 1)));
463 assertEquals("2", getText(stmt, getArg(f, 2)));
464 }
465
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000466 @Test
Laurent Le Brund412c8f2015-06-16 11:12:54 +0000467 public void testForBreakContinue() throws Exception {
468 List<Statement> file = parseFileForSkylark(
469 "def foo():",
470 " for i in [1, 2]:",
471 " break",
472 " continue");
473 assertThat(file).hasSize(1);
474 List<Statement> body = ((FunctionDefStatement) file.get(0)).getStatements();
475 assertThat(body).hasSize(1);
476
477 List<Statement> loop = ((ForStatement) body.get(0)).block();
478 assertThat(loop).hasSize(2);
479
480 assertThat(loop.get(0)).isEqualTo(FlowStatement.BREAK);
481 assertLocation(34, 40, loop.get(0).getLocation());
482
483 assertThat(loop.get(1)).isEqualTo(FlowStatement.CONTINUE);
484 assertLocation(44, 52, loop.get(1).getLocation());
485 }
486
487 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000488 public void testListLiterals1() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000489 ListLiteral list = (ListLiteral) parseExpression("[0,1,2]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000490 assertFalse(list.isTuple());
491 assertThat(list.getElements()).hasSize(3);
492 assertFalse(list.isTuple());
493 for (int i = 0; i < 3; ++i) {
494 assertEquals(i, getIntElem(list, i));
495 }
496 }
497
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000498 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000499 public void testTupleLiterals2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000500 ListLiteral tuple = (ListLiteral) parseExpression("(0,1,2)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000501 assertTrue(tuple.isTuple());
502 assertThat(tuple.getElements()).hasSize(3);
503 assertTrue(tuple.isTuple());
504 for (int i = 0; i < 3; ++i) {
505 assertEquals(i, getIntElem(tuple, i));
506 }
507 }
508
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000509 @Test
Laurent Le Brun56093892015-03-20 13:01:58 +0000510 public void testTupleWithoutParens() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000511 ListLiteral tuple = (ListLiteral) parseExpression("0, 1, 2");
Laurent Le Brun56093892015-03-20 13:01:58 +0000512 assertTrue(tuple.isTuple());
513 assertThat(tuple.getElements()).hasSize(3);
514 assertTrue(tuple.isTuple());
515 for (int i = 0; i < 3; ++i) {
516 assertEquals(i, getIntElem(tuple, i));
517 }
518 }
519
520 @Test
521 public void testTupleWithoutParensWithTrailingComma() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000522 ListLiteral tuple = (ListLiteral) parseExpression("0, 1, 2, 3,");
Laurent Le Brun56093892015-03-20 13:01:58 +0000523 assertTrue(tuple.isTuple());
524 assertThat(tuple.getElements()).hasSize(4);
525 assertTrue(tuple.isTuple());
526 for (int i = 0; i < 4; ++i) {
527 assertEquals(i, getIntElem(tuple, i));
528 }
529 }
530
531 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000532 public void testTupleLiterals3() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000533 ListLiteral emptyTuple = (ListLiteral) parseExpression("()");
Ulf Adams89f012d2015-02-26 13:39:28 +0000534 assertTrue(emptyTuple.isTuple());
535 assertThat(emptyTuple.getElements()).isEmpty();
536 }
537
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000538 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000539 public void testTupleLiterals4() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000540 ListLiteral singletonTuple = (ListLiteral) parseExpression("(42,)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000541 assertTrue(singletonTuple.isTuple());
542 assertThat(singletonTuple.getElements()).hasSize(1);
543 assertEquals(42, getIntElem(singletonTuple, 0));
544 }
545
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000546 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000547 public void testTupleLiterals5() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000548 IntegerLiteral intLit = (IntegerLiteral) parseExpression("(42)"); // not a tuple!
Ulf Adams89f012d2015-02-26 13:39:28 +0000549 assertEquals(42, (int) intLit.getValue());
550 }
551
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000552 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000553 public void testListLiterals6() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000554 ListLiteral emptyList = (ListLiteral) parseExpression("[]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000555 assertFalse(emptyList.isTuple());
556 assertThat(emptyList.getElements()).isEmpty();
557 }
558
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000559 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000560 public void testListLiterals7() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000561 ListLiteral singletonList = (ListLiteral) parseExpression("[42,]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000562 assertFalse(singletonList.isTuple());
563 assertThat(singletonList.getElements()).hasSize(1);
564 assertEquals(42, getIntElem(singletonList, 0));
565 }
566
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000567 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000568 public void testListLiterals8() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000569 ListLiteral singletonList = (ListLiteral) parseExpression("[42]"); // a singleton
Ulf Adams89f012d2015-02-26 13:39:28 +0000570 assertFalse(singletonList.isTuple());
571 assertThat(singletonList.getElements()).hasSize(1);
572 assertEquals(42, getIntElem(singletonList, 0));
573 }
574
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000575 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000576 public void testDictionaryLiterals() throws Exception {
577 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000578 (DictionaryLiteral) parseExpression("{1:42}"); // a singleton dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000579 assertThat(dictionaryList.getEntries()).hasSize(1);
580 DictionaryEntryLiteral tuple = getElem(dictionaryList, 0);
581 assertEquals(1, getIntElem(tuple, true));
582 assertEquals(42, getIntElem(tuple, false));
583 }
584
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000585 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000586 public void testDictionaryLiterals1() throws Exception {
587 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000588 (DictionaryLiteral) parseExpression("{}"); // an empty dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000589 assertThat(dictionaryList.getEntries()).isEmpty();
590 }
591
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000592 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000593 public void testDictionaryLiterals2() throws Exception {
594 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000595 (DictionaryLiteral) parseExpression("{1:42,}"); // a singleton dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000596 assertThat(dictionaryList.getEntries()).hasSize(1);
597 DictionaryEntryLiteral tuple = getElem(dictionaryList, 0);
598 assertEquals(1, getIntElem(tuple, true));
599 assertEquals(42, getIntElem(tuple, false));
600 }
601
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000602 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000603 public void testDictionaryLiterals3() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000604 DictionaryLiteral dictionaryList = (DictionaryLiteral) parseExpression("{1:42,2:43,3:44}");
Ulf Adams89f012d2015-02-26 13:39:28 +0000605 assertThat(dictionaryList.getEntries()).hasSize(3);
606 for (int i = 0; i < 3; i++) {
607 DictionaryEntryLiteral tuple = getElem(dictionaryList, i);
608 assertEquals(i + 1, getIntElem(tuple, true));
609 assertEquals(i + 42, getIntElem(tuple, false));
610 }
611 }
612
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000613 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000614 public void testListLiterals9() throws Exception {
615 ListLiteral singletonList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000616 (ListLiteral) parseExpression("[ abi + opt_level + \'/include\' ]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000617 assertFalse(singletonList.isTuple());
618 assertThat(singletonList.getElements()).hasSize(1);
619 }
620
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000621 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000622 public void testListComprehensionSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000623 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000624
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000625 parseExpression("[x for");
626 assertContainsEvent("syntax error at 'newline'");
627 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000628
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000629 parseExpression("[x for x");
630 assertContainsEvent("syntax error at 'newline'");
631 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000632
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000633 parseExpression("[x for x in");
634 assertContainsEvent("syntax error at 'newline'");
635 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000636
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000637 parseExpression("[x for x in []");
638 assertContainsEvent("syntax error at 'newline'");
639 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000640
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000641 parseExpression("[x for x for y in ['a']]");
642 assertContainsEvent("syntax error at 'for'");
643 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000644 }
645
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000646 @Test
Laurent Le Brun52021662015-05-18 09:28:26 +0000647 public void testListComprehensionEmptyList() throws Exception {
648 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
649 "['foo/%s.java' % x for x in []]")).getClauses();
650 assertThat(clauses).hasSize(1);
651 assertThat(clauses.get(0).getExpression().toString()).isEqualTo("[]");
652 assertThat(clauses.get(0).getLValue().getExpression().toString()).isEqualTo("x");
653 }
654
655 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000656 public void testListComprehension() throws Exception {
Laurent Le Brun52021662015-05-18 09:28:26 +0000657 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
658 "['foo/%s.java' % x for x in ['bar', 'wiz', 'quux']]")).getClauses();
659 assertThat(clauses).hasSize(1);
660 assertThat(clauses.get(0).getLValue().getExpression().toString()).isEqualTo("x");
661 assertThat(clauses.get(0).getExpression()).isInstanceOf(ListLiteral.class);
662 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000663
Laurent Le Brun52021662015-05-18 09:28:26 +0000664 @Test
665 public void testForForListComprehension() throws Exception {
666 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
667 "['%s/%s.java' % (x, y) for x in ['foo', 'bar'] for y in list]")).getClauses();
668 assertThat(clauses).hasSize(2);
669 assertThat(clauses.get(0).getLValue().getExpression().toString()).isEqualTo("x");
670 assertThat(clauses.get(0).getExpression()).isInstanceOf(ListLiteral.class);
671 assertThat(clauses.get(1).getLValue().getExpression().toString()).isEqualTo("y");
Florian Weikert6f864c32015-07-23 11:26:39 +0000672 assertThat(clauses.get(1).getExpression()).isInstanceOf(Identifier.class);
Ulf Adams89f012d2015-02-26 13:39:28 +0000673 }
674
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000675 @Test
Laurent Le Brun9060e162015-04-02 10:07:28 +0000676 public void testParserRecovery() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000677 setFailFast(false);
678 List<Statement> statements = parseFileForSkylark(
Laurent Le Brun9060e162015-04-02 10:07:28 +0000679 "def foo():",
Laurent Le Brune3f4ed72015-05-08 14:47:26 +0000680 " a = 2 for 4", // parse error
Laurent Le Brun9060e162015-04-02 10:07:28 +0000681 " b = [3, 4]",
682 "",
683 "d = 4 ada", // parse error
684 "",
685 "def bar():",
686 " a = [3, 4]",
687 " b = 2 + + 5", // parse error
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000688 "");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000689
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000690 assertThat(getEventCollector()).hasSize(3);
Laurent Le Brune3f4ed72015-05-08 14:47:26 +0000691 assertContainsEvent("syntax error at 'for': expected newline");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000692 assertContainsEvent("syntax error at 'ada': expected newline");
693 assertContainsEvent("syntax error at '+': expected expression");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000694 assertThat(statements).hasSize(3);
695 }
696
697 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000698 public void testParserContainsErrorsIfSyntaxException() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000699 setFailFast(false);
700 parseExpression("'foo' %%");
701 assertContainsEvent("syntax error at '%'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000702 }
703
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000704 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000705 public void testParserDoesNotContainErrorsIfSuccess() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000706 parseExpression("'foo'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000707 }
708
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000709 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000710 public void testParserContainsErrors() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000711 setFailFast(false);
Francois-Rene Rideau5a94e592015-09-04 19:13:47 +0000712 parseFile("+");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000713 assertContainsEvent("syntax error at '+'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000714 }
715
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000716 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000717 public void testSemicolonAndNewline() throws Exception {
718 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000719 "foo='bar'; foo(bar)",
720 "",
721 "foo='bar'; foo(bar)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000722 assertThat(stmts).hasSize(4);
723 }
724
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000725 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000726 public void testSemicolonAndNewline2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000727 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000728 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000729 "foo='foo' error(bar)",
730 "",
731 "");
732 assertContainsEvent("syntax error at 'error'");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000733 assertThat(stmts).hasSize(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000734 }
735
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000736 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000737 public void testExprAsStatement() throws Exception {
738 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000739 "li = []",
740 "li.append('a.c')",
741 "\"\"\" string comment \"\"\"",
742 "foo(bar)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000743 assertThat(stmts).hasSize(4);
744 }
745
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000746 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000747 public void testParseBuildFileWithSingeRule() throws Exception {
748 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000749 "genrule(name = 'foo',",
750 " srcs = ['input.csv'],",
751 " outs = [ 'result.txt',",
752 " 'result.log'],",
753 " cmd = 'touch result.txt result.log')",
754 "");
Ulf Adams89f012d2015-02-26 13:39:28 +0000755 assertThat(stmts).hasSize(1);
756 }
757
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000758 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000759 public void testParseBuildFileWithMultipleRules() throws Exception {
760 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000761 "genrule(name = 'foo',",
762 " srcs = ['input.csv'],",
763 " outs = [ 'result.txt',",
764 " 'result.log'],",
765 " cmd = 'touch result.txt result.log')",
766 "",
767 "genrule(name = 'bar',",
768 " srcs = ['input.csv'],",
769 " outs = [ 'graph.svg'],",
770 " cmd = 'touch graph.svg')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000771 assertThat(stmts).hasSize(2);
772 }
773
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000774 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000775 public void testParseBuildFileWithComments() throws Exception {
776 Parser.ParseResult result = parseFileWithComments(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000777 "# Test BUILD file",
778 "# with multi-line comment",
779 "",
780 "genrule(name = 'foo',",
781 " srcs = ['input.csv'],",
782 " outs = [ 'result.txt',",
783 " 'result.log'],",
784 " cmd = 'touch result.txt result.log')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000785 assertThat(result.statements).hasSize(1);
786 assertThat(result.comments).hasSize(2);
787 }
788
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000789 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000790 public void testParseBuildFileWithManyComments() throws Exception {
791 Parser.ParseResult result = parseFileWithComments(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000792 "# 1",
793 "# 2",
794 "",
795 "# 4 ",
796 "# 5",
797 "#", // 6 - find empty comment for syntax highlighting
798 "# 7 ",
799 "# 8",
800 "genrule(name = 'foo',",
801 " srcs = ['input.csv'],",
802 " # 11",
803 " outs = [ 'result.txt',",
804 " 'result.log'], # 13",
805 " cmd = 'touch result.txt result.log')",
806 "# 15");
Ulf Adams89f012d2015-02-26 13:39:28 +0000807 assertThat(result.statements).hasSize(1); // Single genrule
808 StringBuilder commentLines = new StringBuilder();
809 for (Comment comment : result.comments) {
810 // Comments start and end on the same line
811 assertEquals(comment.getLocation().getStartLineAndColumn().getLine() + " ends on "
812 + comment.getLocation().getEndLineAndColumn().getLine(),
813 comment.getLocation().getStartLineAndColumn().getLine(),
814 comment.getLocation().getEndLineAndColumn().getLine());
815 commentLines.append('(');
816 commentLines.append(comment.getLocation().getStartLineAndColumn().getLine());
817 commentLines.append(',');
818 commentLines.append(comment.getLocation().getStartLineAndColumn().getColumn());
819 commentLines.append(") ");
820 }
821 assertWithMessage("Found: " + commentLines)
822 .that(result.comments.size()).isEqualTo(10); // One per '#'
823 }
824
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000825 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000826 public void testMissingComma() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000827 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000828 // Regression test.
829 // Note: missing comma after name='foo'
830 parseFile("genrule(name = 'foo'\n"
831 + " srcs = ['in'])");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000832 assertContainsEvent("syntax error at 'srcs'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000833 }
834
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000835 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000836 public void testDoubleSemicolon() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000837 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000838 // Regression test.
839 parseFile("x = 1; ; x = 2;");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000840 assertContainsEvent("syntax error at ';'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000841 }
842
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000843 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000844 public void testFunctionDefinitionErrorRecovery() throws Exception {
845 // Parser skips over entire function definitions, and reports a meaningful
846 // error.
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000847 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000848 List<Statement> stmts = parseFile(
849 "x = 1;\n"
850 + "def foo(x, y, **z):\n"
851 + " # a comment\n"
852 + " x = 2\n"
853 + " foo(bar)\n"
854 + " return z\n"
855 + "x = 3");
856 assertThat(stmts).hasSize(2);
857 }
858
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000859 @Test
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000860 public void testFunctionDefinitionIgnoredEvenWithUnsupportedKeyword() throws Exception {
861 // Parser skips over entire function definitions without reporting error,
862 // when parsePython is set to true.
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000863 List<Statement> stmts = parseFileWithPython(
864 "x = 1;",
865 "def foo(x, y, **z):",
866 " try:",
867 " x = 2",
868 " with: pass",
869 " return 2",
870 "x = 3");
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000871 assertThat(stmts).hasSize(2);
872 }
873
874 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000875 public void testFunctionDefinitionIgnored() throws Exception {
876 // Parser skips over entire function definitions without reporting error,
877 // when parsePython is set to true.
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000878 List<Statement> stmts = parseFileWithPython(
879 "x = 1;",
880 "def foo(x, y, **z):",
881 " # a comment",
882 " if true:",
883 " x = 2",
884 " foo(bar)",
885 " return z",
886 "x = 3");
Ulf Adams89f012d2015-02-26 13:39:28 +0000887 assertThat(stmts).hasSize(2);
888
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000889 stmts = parseFileWithPython(
890 "x = 1;",
891 "def foo(x, y, **z): return x",
892 "x = 3");
Ulf Adams89f012d2015-02-26 13:39:28 +0000893 assertThat(stmts).hasSize(2);
894 }
895
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000896 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000897 public void testMissingBlock() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000898 setFailFast(false);
899 List<Statement> stmts = parseFileWithPython(
900 "x = 1;",
901 "def foo(x):",
902 "x = 2;\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000903 assertThat(stmts).hasSize(2);
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000904 assertContainsEvent("expected an indented block");
Ulf Adams89f012d2015-02-26 13:39:28 +0000905 }
906
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000907 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000908 public void testInvalidDef() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000909 setFailFast(false);
910 parseFileWithPython(
911 "x = 1;",
912 "def foo(x)",
913 "x = 2;\n");
914 assertContainsEvent("syntax error at 'EOF'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000915 }
916
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000917 @Test
Laurent Le Brun5f674452015-03-17 19:29:13 +0000918 public void testDefSingleLine() throws Exception {
919 List<Statement> statements = parseFileForSkylark(
920 "def foo(): x = 1; y = 2\n");
921 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
922 assertThat(stmt.getStatements()).hasSize(2);
923 }
924
925 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000926 public void testSkipIfBlock() throws Exception {
927 // Skip over 'if' blocks, when parsePython is set
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000928 List<Statement> stmts = parseFileWithPython(
929 "x = 1;",
930 "if x == 1:",
931 " foo(x)",
932 "else:",
933 " bar(x)",
934 "x = 3;\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000935 assertThat(stmts).hasSize(2);
936 }
937
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000938 @Test
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000939 public void testPass() throws Exception {
940 List<Statement> statements = parseFileForSkylark("pass\n");
941 assertThat(statements).isEmpty();
942 }
943
944 @Test
945 public void testForPass() throws Exception {
946 List<Statement> statements = parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000947 "def foo():",
948 " pass\n");
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000949
950 assertThat(statements).hasSize(1);
951 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
952 assertThat(stmt.getStatements()).isEmpty();
953 }
954
955 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000956 public void testSkipIfBlockFail() throws Exception {
957 // Do not parse 'if' blocks, when parsePython is not set
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000958 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000959 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000960 "x = 1;",
961 "if x == 1:",
962 " x = 2",
963 "x = 3;\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000964 assertThat(stmts).hasSize(2);
Laurent Le Brunb13a4382015-06-30 14:20:45 +0000965 assertContainsEvent("This is not supported in BUILD files");
Ulf Adams89f012d2015-02-26 13:39:28 +0000966 }
967
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000968 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000969 public void testForLoopMultipleVariables() throws Exception {
Laurent Le Brun185392d2015-03-20 14:41:25 +0000970 List<Statement> stmts1 = parseFile("[ i for i, j, k in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000971 assertThat(stmts1).hasSize(1);
972
Laurent Le Brun185392d2015-03-20 14:41:25 +0000973 List<Statement> stmts2 = parseFile("[ i for i, j in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000974 assertThat(stmts2).hasSize(1);
975
Laurent Le Brun185392d2015-03-20 14:41:25 +0000976 List<Statement> stmts3 = parseFile("[ i for (i, j, k) in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000977 assertThat(stmts3).hasSize(1);
978 }
Googlercc0d9952015-08-10 12:01:34 +0000979
980 @Test
981 public void testReturnNone() throws Exception {
982 List<Statement> defNone = parseFileForSkylark("def foo():", " return None\n");
983 assertThat(defNone).hasSize(1);
984
985 List<Statement> bodyNone = ((FunctionDefStatement) defNone.get(0)).getStatements();
986 assertThat(bodyNone).hasSize(1);
987
988 ReturnStatement returnNone = (ReturnStatement) bodyNone.get(0);
989 assertEquals("None", ((Identifier) returnNone.getReturnExpression()).getName());
990
991 int i = 0;
992 for (String end : new String[]{";", "\n"}) {
993 List<Statement> defNoExpr = parseFileForSkylark("def bar" + i + "():", " return" + end);
994 i++;
995 assertThat(defNoExpr).hasSize(1);
996
997 List<Statement> bodyNoExpr = ((FunctionDefStatement) defNoExpr.get(0)).getStatements();
998 assertThat(bodyNoExpr).hasSize(1);
999
1000 ReturnStatement returnNoExpr = (ReturnStatement) bodyNoExpr.get(0);
1001 Identifier none = (Identifier) returnNoExpr.getReturnExpression();
1002 assertEquals("None", none.getName());
1003 assertLocation(
1004 returnNoExpr.getLocation().getStartOffset(),
1005 returnNoExpr.getLocation().getEndOffset(),
1006 none.getLocation());
1007 }
1008 }
Ulf Adams89f012d2015-02-26 13:39:28 +00001009
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001010 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001011 public void testForLoopBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001012 setFailFast(false);
Laurent Le Brun185392d2015-03-20 14:41:25 +00001013 parseFile("[1 for (a, b, c in var]\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001014 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001015 }
1016
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001017 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001018 public void testForLoopBadSyntax2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001019 setFailFast(false);
Laurent Le Brun185392d2015-03-20 14:41:25 +00001020 parseFile("[1 for in var]\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001021 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001022 }
1023
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001024 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001025 public void testFunCallBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001026 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001027 parseFile("f(1,\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001028 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001029 }
1030
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001031 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001032 public void testFunCallBadSyntax2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001033 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001034 parseFile("f(1, 5, ,)\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001035 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001036 }
1037
Florian Weikert308c0bf2015-07-10 10:46:56 +00001038 private static final String DOUBLE_SLASH_LOAD = "load('//foo/bar/file', 'test')\n";
1039 private static final String DOUBLE_SLASH_ERROR =
1040 "First argument of load() is a path, not a label. It should start with a "
1041 + "single slash if it is an absolute path.";
1042
1043 @Test
1044 public void testLoadDoubleSlashBuild() throws Exception {
1045 setFailFast(false);
1046 parseFile(DOUBLE_SLASH_LOAD);
1047 assertContainsEvent(DOUBLE_SLASH_ERROR);
1048 }
1049
1050 @Test
1051 public void testLoadDoubleSlashSkylark() throws Exception {
1052 setFailFast(false);
1053 parseFileForSkylark(DOUBLE_SLASH_LOAD);
1054 assertContainsEvent(DOUBLE_SLASH_ERROR);
1055 }
1056
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001057 @Test
Laurent Le Brun73a98492015-03-17 15:46:19 +00001058 public void testLoadNoSymbol() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001059 setFailFast(false);
Laurent Le Brun73a98492015-03-17 15:46:19 +00001060 parseFileForSkylark("load('/foo/bar/file')\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001061 assertContainsEvent("syntax error");
Laurent Le Brun73a98492015-03-17 15:46:19 +00001062 }
1063
1064 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001065 public void testLoadOneSymbol() throws Exception {
1066 List<Statement> statements = parseFileForSkylark(
1067 "load('/foo/bar/file', 'fun_test')\n");
1068 LoadStatement stmt = (LoadStatement) statements.get(0);
1069 assertEquals("/foo/bar/file.bzl", stmt.getImportPath().toString());
1070 assertThat(stmt.getSymbols()).hasSize(1);
1071 }
1072
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001073 @Test
Laurent Le Brun59f587a2015-03-16 14:51:36 +00001074 public void testLoadOneSymbolWithTrailingComma() throws Exception {
1075 List<Statement> statements = parseFileForSkylark(
1076 "load('/foo/bar/file', 'fun_test',)\n");
1077 LoadStatement stmt = (LoadStatement) statements.get(0);
1078 assertEquals("/foo/bar/file.bzl", stmt.getImportPath().toString());
1079 assertThat(stmt.getSymbols()).hasSize(1);
1080 }
1081
1082 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001083 public void testLoadMultipleSymbols() throws Exception {
1084 List<Statement> statements = parseFileForSkylark(
1085 "load('file', 'foo', 'bar')\n");
1086 LoadStatement stmt = (LoadStatement) statements.get(0);
1087 assertEquals("file.bzl", stmt.getImportPath().toString());
1088 assertThat(stmt.getSymbols()).hasSize(2);
1089 }
1090
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001091 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001092 public void testLoadSyntaxError() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001093 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001094 parseFileForSkylark("load(non_quoted, 'a')\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001095 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001096 }
1097
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001098 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001099 public void testLoadSyntaxError2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001100 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001101 parseFileForSkylark("load('non_quoted', a)\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001102 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001103 }
1104
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001105 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001106 public void testLoadNotAtTopLevel() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001107 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001108 parseFileForSkylark("if 1: load(8)\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001109 assertContainsEvent("function 'load' does not exist");
Ulf Adams89f012d2015-02-26 13:39:28 +00001110 }
1111
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001112 @Test
Florian Weikert9d659ad2015-07-23 14:44:36 +00001113 public void testLoadAlias() throws Exception {
1114 runLoadAliasTestForSymbols("my_alias = 'lawl'", "my_alias");
1115 }
1116
1117 @Test
1118 public void testLoadAliasMultiple() throws Exception {
1119 runLoadAliasTestForSymbols(
1120 "my_alias = 'lawl', 'lol', next_alias = 'rofl'", "my_alias", "lol", "next_alias");
1121 }
1122
1123 private void runLoadAliasTestForSymbols(String loadSymbolString, String... expectedSymbols) {
1124 List<Statement> statements =
1125 parseFileForSkylark(String.format("load('/foo/bar/file', %s)\n", loadSymbolString));
1126 LoadStatement stmt = (LoadStatement) statements.get(0);
1127 ImmutableList<Identifier> actualSymbols = stmt.getSymbols();
1128
1129 assertThat(actualSymbols).hasSize(expectedSymbols.length);
1130
1131 List<String> actualSymbolNames = new LinkedList<>();
1132
1133 for (Identifier identifier : actualSymbols) {
1134 actualSymbolNames.add(identifier.getName());
1135 }
1136
1137 assertThat(actualSymbolNames).containsExactly((Object[]) expectedSymbols);
1138 }
1139
1140 @Test
1141 public void testLoadAliasSyntaxError() throws Exception {
1142 setFailFast(false);
1143 parseFileForSkylark("load('/foo', test1 = )\n");
1144 assertContainsEvent("syntax error at ')': expected string");
1145
1146 parseFileForSkylark("load('/foo', test2 = 1)\n");
1147 assertContainsEvent("syntax error at '1': expected string");
1148
1149 parseFileForSkylark("load('/foo', test3 = old)\n");
1150 assertContainsEvent("syntax error at 'old': expected string");
1151 }
1152
1153 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001154 public void testParseErrorNotComparison() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001155 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001156 parseFile("2 < not 3");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001157 assertContainsEvent("syntax error at 'not'");
Ulf Adams89f012d2015-02-26 13:39:28 +00001158 }
1159
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001160 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001161 public void testNotWithArithmeticOperatorsBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001162 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001163 parseFile("0 + not 0");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001164 assertContainsEvent("syntax error at 'not'");
Ulf Adams89f012d2015-02-26 13:39:28 +00001165 }
1166
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001167 @Test
Laurent Le Brunb3266382015-05-27 16:14:43 +00001168 public void testKwargsForbidden() throws Exception {
1169 setFailFast(false);
1170 parseFile("func(**dict)");
1171 assertContainsEvent("**kwargs arguments are not allowed in BUILD files");
1172 }
1173
1174 @Test
1175 public void testArgsForbidden() throws Exception {
1176 setFailFast(false);
1177 parseFile("func(*array)");
1178 assertContainsEvent("*args arguments are not allowed in BUILD files");
1179 }
1180
1181 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001182 public void testOptionalArgBeforeMandatoryArgInFuncDef() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001183 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001184 parseFileForSkylark("def func(a, b = 'a', c):\n return 0\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001185 assertContainsEvent(
Ulf Adams89f012d2015-02-26 13:39:28 +00001186 "a mandatory positional parameter must not follow an optional parameter");
1187 }
1188
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001189 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001190 public void testKwargBeforePositionalArg() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001191 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001192 parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001193 "def func(a, b): return a + b",
1194 "func(**{'b': 1}, 'a')");
1195 assertContainsEvent("unexpected tokens after kwarg");
Ulf Adams89f012d2015-02-26 13:39:28 +00001196 }
1197
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001198 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001199 public void testDuplicateKwarg() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001200 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001201 parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001202 "def func(a, b): return a + b",
1203 "func(**{'b': 1}, **{'a': 2})");
1204 assertContainsEvent("unexpected tokens after kwarg");
Ulf Adams89f012d2015-02-26 13:39:28 +00001205 }
1206
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001207 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001208 public void testUnnamedStar() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001209 setFailFast(false);
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001210 List<Statement> statements = parseFileForSkylark(
1211 "def func(a, b1=2, b2=3, *, c1, d=4, c2): return a + b1 + b2 + c1 + c2 + d\n");
1212 assertThat(statements).hasSize(1);
1213 assertThat(statements.get(0)).isInstanceOf(FunctionDefStatement.class);
1214 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
Laurent Le Brun4baefdc2015-09-04 11:27:46 +00001215 FunctionSignature sig = stmt.getSignature().getSignature();
Francois-Rene Rideau012f7892015-03-31 17:27:01 +00001216 // Note the reordering of optional named-only at the end.
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001217 assertThat(sig.getNames()).isEqualTo(ImmutableList.<String>of(
Francois-Rene Rideau012f7892015-03-31 17:27:01 +00001218 "a", "b1", "b2", "c1", "c2", "d"));
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001219 FunctionSignature.Shape shape = sig.getShape();
1220 assertThat(shape.getMandatoryPositionals()).isEqualTo(1);
1221 assertThat(shape.getOptionalPositionals()).isEqualTo(2);
1222 assertThat(shape.getMandatoryNamedOnly()).isEqualTo(2);
1223 assertThat(shape.getOptionalNamedOnly()).isEqualTo(1);
Ulf Adams89f012d2015-02-26 13:39:28 +00001224 }
1225
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001226 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001227 public void testTopLevelForFails() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001228 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001229 parseFileForSkylark("for i in []: 0\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001230 assertContainsEvent(
Ulf Adams89f012d2015-02-26 13:39:28 +00001231 "for loops are not allowed on top-level. Put it into a function");
1232 }
1233
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001234 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001235 public void testNestedFunctionFails() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001236 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001237 parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001238 "def func(a):",
1239 " def bar(): return 0",
1240 " return bar()",
1241 "");
1242 assertContainsEvent(
Ulf Adams89f012d2015-02-26 13:39:28 +00001243 "nested functions are not allowed. Move the function to top-level");
1244 }
1245
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001246 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001247 public void testIncludeFailureSkylark() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001248 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001249 parseFileForSkylark("include('//foo:bar')");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001250 assertContainsEvent("function 'include' does not exist");
Ulf Adams89f012d2015-02-26 13:39:28 +00001251 }
1252
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001253 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001254 public void testIncludeFailure() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001255 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001256 parseFile("include('nonexistent')\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001257 assertContainsEvent("Invalid label 'nonexistent'");
Ulf Adams89f012d2015-02-26 13:39:28 +00001258 }
1259}