blob: 95b87aa72032d1a620da09c53761e09a5beebcae [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Ulf Adams89f012d2015-02-26 13:39:28 +00002//
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
Lukacs Berkid9e733d2015-09-18 08:18:11 +000023import com.google.common.base.Joiner;
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +000024import com.google.common.collect.ImmutableList;
Ulf Adams89f012d2015-02-26 13:39:28 +000025import com.google.devtools.build.lib.events.Location;
26import com.google.devtools.build.lib.syntax.DictionaryLiteral.DictionaryEntryLiteral;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000027import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
Ulf Adams89f012d2015-02-26 13:39:28 +000028
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000029import org.junit.Before;
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000030import org.junit.Test;
31import org.junit.runner.RunWith;
32import org.junit.runners.JUnit4;
33
Florian Weikert9d659ad2015-07-23 14:44:36 +000034import java.util.LinkedList;
Ulf Adams89f012d2015-02-26 13:39:28 +000035import java.util.List;
36
37/**
38 * Tests of parser behaviour.
Ulf Adams89f012d2015-02-26 13:39:28 +000039 */
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000040@RunWith(JUnit4.class)
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000041public class ParserTest extends EvaluationTestCase {
42
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000043 Environment buildEnvironment;
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000044
45 @Before
46 @Override
47 public void setUp() throws Exception {
48 super.setUp();
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000049 buildEnvironment = newBuildEnvironment();
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000050 }
51
52 private Parser.ParseResult parseFileWithComments(String... input) {
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000053 return buildEnvironment.parseFileWithComments(input);
Francois-Rene Rideau5a94e592015-09-04 19:13:47 +000054 }
55
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000056 /** Parses build code (not Skylark) */
57 @Override
58 protected List<Statement> parseFile(String... input) {
59 return buildEnvironment.parseFile(input);
60 }
61
62 /** Parses a build code (not Skylark) with PythonProcessing enabled */
63 private List<Statement> parseFileWithPython(String... input) {
64 return Parser.parseFile(
Lukacs Berkid9e733d2015-09-18 08:18:11 +000065 ParserInputSource.create(Joiner.on("\n").join(input), null),
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000066 getEventHandler(),
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000067 /*parsePython=*/true).statements;
68 }
69
70 /** Parses Skylark code */
71 private List<Statement> parseFileForSkylark(String... input) {
72 return env.parseFile(input);
73 }
Ulf Adams89f012d2015-02-26 13:39:28 +000074
75 private static String getText(String text, ASTNode node) {
76 return text.substring(node.getLocation().getStartOffset(),
77 node.getLocation().getEndOffset());
78 }
79
80 // helper func for testListLiterals:
81 private static int getIntElem(DictionaryEntryLiteral entry, boolean key) {
82 return ((IntegerLiteral) (key ? entry.getKey() : entry.getValue())).getValue();
83 }
84
85 // helper func for testListLiterals:
86 private static DictionaryEntryLiteral getElem(DictionaryLiteral list, int index) {
87 return list.getEntries().get(index);
88 }
89
90 // helper func for testListLiterals:
91 private static int getIntElem(ListLiteral list, int index) {
92 return ((IntegerLiteral) list.getElements().get(index)).getValue();
93 }
94
95 // helper func for testListLiterals:
96 private static Expression getElem(ListLiteral list, int index) {
97 return list.getElements().get(index);
98 }
99
100 // helper func for testing arguments:
101 private static Expression getArg(FuncallExpression f, int index) {
102 return f.getArguments().get(index).getValue();
103 }
104
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000105 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000106 public void testPrecedence1() throws Exception {
107 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000108 (BinaryOperatorExpression) parseExpression("'%sx' % 'foo' + 'bar'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000109
110 assertEquals(Operator.PLUS, e.getOperator());
111 }
112
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000113 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000114 public void testPrecedence2() throws Exception {
115 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000116 (BinaryOperatorExpression) parseExpression("('%sx' % 'foo') + 'bar'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000117 assertEquals(Operator.PLUS, e.getOperator());
118 }
119
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000120 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000121 public void testPrecedence3() throws Exception {
122 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000123 (BinaryOperatorExpression) parseExpression("'%sx' % ('foo' + 'bar')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000124 assertEquals(Operator.PERCENT, e.getOperator());
125 }
126
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000127 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000128 public void testPrecedence4() throws Exception {
129 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000130 (BinaryOperatorExpression) parseExpression("1 + - (2 - 3)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000131 assertEquals(Operator.PLUS, e.getOperator());
132 }
133
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000134 @Test
Laurent Le Brun7bda87e2015-08-24 15:13:53 +0000135 public void testPrecedence5() throws Exception {
136 BinaryOperatorExpression e =
137 (BinaryOperatorExpression) parseExpression("2 * x | y + 1");
138 assertEquals(Operator.PIPE, e.getOperator());
139 }
140
141 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000142 public void testUnaryMinusExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000143 FuncallExpression e = (FuncallExpression) parseExpression("-5");
144 FuncallExpression e2 = (FuncallExpression) parseExpression("- 5");
Ulf Adams89f012d2015-02-26 13:39:28 +0000145
146 assertEquals("-", e.getFunction().getName());
147 assertEquals("-", e2.getFunction().getName());
148
149 assertThat(e.getArguments()).hasSize(1);
150 assertEquals(1, e.getNumPositionalArguments());
151
152 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
153 assertEquals(5, (int) arg0.getValue());
154 }
155
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000156 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000157 public void testFuncallExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000158 FuncallExpression e = (FuncallExpression) parseExpression("foo(1, 2, bar=wiz)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000159
Florian Weikert6f864c32015-07-23 11:26:39 +0000160 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000161 assertEquals("foo", ident.getName());
162
163 assertThat(e.getArguments()).hasSize(3);
164 assertEquals(2, e.getNumPositionalArguments());
165
166 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
167 assertEquals(1, (int) arg0.getValue());
168
169 IntegerLiteral arg1 = (IntegerLiteral) e.getArguments().get(1).getValue();
170 assertEquals(2, (int) arg1.getValue());
171
172 Argument.Passed arg2 = e.getArguments().get(2);
173 assertEquals("bar", arg2.getName());
Florian Weikert6f864c32015-07-23 11:26:39 +0000174 Identifier arg2val = (Identifier) arg2.getValue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000175 assertEquals("wiz", arg2val.getName());
176 }
177
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000178 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000179 public void testMethCallExpr() throws Exception {
180 FuncallExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000181 (FuncallExpression) parseExpression("foo.foo(1, 2, bar=wiz)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000182
Florian Weikert6f864c32015-07-23 11:26:39 +0000183 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000184 assertEquals("foo", ident.getName());
185
186 assertThat(e.getArguments()).hasSize(3);
187 assertEquals(2, e.getNumPositionalArguments());
188
189 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
190 assertEquals(1, (int) arg0.getValue());
191
192 IntegerLiteral arg1 = (IntegerLiteral) e.getArguments().get(1).getValue();
193 assertEquals(2, (int) arg1.getValue());
194
195 Argument.Passed arg2 = e.getArguments().get(2);
196 assertEquals("bar", arg2.getName());
Florian Weikert6f864c32015-07-23 11:26:39 +0000197 Identifier arg2val = (Identifier) arg2.getValue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000198 assertEquals("wiz", arg2val.getName());
199 }
200
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000201 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000202 public void testChainedMethCallExpr() throws Exception {
203 FuncallExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000204 (FuncallExpression) parseExpression("foo.replace().split(1)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000205
Florian Weikert6f864c32015-07-23 11:26:39 +0000206 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000207 assertEquals("split", ident.getName());
208
209 assertThat(e.getArguments()).hasSize(1);
210 assertEquals(1, e.getNumPositionalArguments());
211
212 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
213 assertEquals(1, (int) arg0.getValue());
214 }
215
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000216 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000217 public void testPropRefExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000218 DotExpression e = (DotExpression) parseExpression("foo.foo");
Ulf Adams89f012d2015-02-26 13:39:28 +0000219
Florian Weikert6f864c32015-07-23 11:26:39 +0000220 Identifier ident = e.getField();
Ulf Adams89f012d2015-02-26 13:39:28 +0000221 assertEquals("foo", ident.getName());
222 }
223
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000224 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000225 public void testStringMethExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000226 FuncallExpression e = (FuncallExpression) parseExpression("'foo'.foo()");
Ulf Adams89f012d2015-02-26 13:39:28 +0000227
Florian Weikert6f864c32015-07-23 11:26:39 +0000228 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000229 assertEquals("foo", ident.getName());
230
231 assertThat(e.getArguments()).isEmpty();
232 }
233
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000234 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000235 public void testStringLiteralOptimizationValue() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000236 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000237 assertEquals("abcdef", l.value);
238 }
239
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000240 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000241 public void testStringLiteralOptimizationToString() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000242 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000243 assertEquals("'abcdef'", l.toString());
244 }
245
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000246 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000247 public void testStringLiteralOptimizationLocation() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000248 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000249 assertEquals(0, l.getLocation().getStartOffset());
250 assertEquals(13, l.getLocation().getEndOffset());
251 }
252
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000253 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000254 public void testStringLiteralOptimizationDifferentQuote() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000255 assertThat(parseExpression("'abc' + \"def\"")).isInstanceOf(BinaryOperatorExpression.class);
Ulf Adams89f012d2015-02-26 13:39:28 +0000256 }
257
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000258 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000259 public void testSubstring() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000260 FuncallExpression e = (FuncallExpression) parseExpression("'FOO.CC'[:].lower()[1:]");
Laurent Le Bruneeef30f2015-03-16 15:12:35 +0000261 assertEquals("$slice", e.getFunction().getName());
Ulf Adams89f012d2015-02-26 13:39:28 +0000262 assertThat(e.getArguments()).hasSize(2);
263
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000264 e = (FuncallExpression) parseExpression("'FOO.CC'.lower()[1:].startswith('oo')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000265 assertEquals("startswith", e.getFunction().getName());
266 assertThat(e.getArguments()).hasSize(1);
267
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000268 e = (FuncallExpression) parseExpression("'FOO.CC'[1:][:2]");
Laurent Le Bruneeef30f2015-03-16 15:12:35 +0000269 assertEquals("$slice", e.getFunction().getName());
Ulf Adams89f012d2015-02-26 13:39:28 +0000270 assertThat(e.getArguments()).hasSize(2);
271 }
272
273 private void assertLocation(int start, int end, Location location)
274 throws Exception {
275 int actualStart = location.getStartOffset();
276 int actualEnd = location.getEndOffset();
277
278 if (actualStart != start || actualEnd != end) {
279 fail("Expected location = [" + start + ", " + end + "), found ["
280 + actualStart + ", " + actualEnd + ")");
281 }
282 }
283
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000284 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000285 public void testErrorRecovery() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000286 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000287
Laurent Le Brun443aaae2015-04-21 19:49:49 +0000288 String expr = "f(1, [x for foo foo foo foo], 3)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000289 FuncallExpression e = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000290
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000291 assertContainsEvent("syntax error at 'foo'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000292
293 // Test that the actual parameters are: (1, $error$, 3):
294
Florian Weikert6f864c32015-07-23 11:26:39 +0000295 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000296 assertEquals("f", ident.getName());
297
298 assertThat(e.getArguments()).hasSize(3);
299 assertEquals(3, e.getNumPositionalArguments());
300
301 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
302 assertEquals(1, (int) arg0.getValue());
303
304 Argument.Passed arg1 = e.getArguments().get(1);
Florian Weikert6f864c32015-07-23 11:26:39 +0000305 Identifier arg1val = ((Identifier) arg1.getValue());
Ulf Adams89f012d2015-02-26 13:39:28 +0000306 assertEquals("$error$", arg1val.getName());
307
Laurent Le Brun443aaae2015-04-21 19:49:49 +0000308 assertLocation(5, 29, arg1val.getLocation());
309 assertEquals("[x for foo foo foo foo]", expr.substring(5, 28));
310 assertEquals(30, arg1val.getLocation().getEndLineAndColumn().getColumn());
Ulf Adams89f012d2015-02-26 13:39:28 +0000311
312 IntegerLiteral arg2 = (IntegerLiteral) e.getArguments().get(2).getValue();
313 assertEquals(3, (int) arg2.getValue());
314 }
315
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000316 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000317 public void testDoesntGetStuck() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000318 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000319
320 // Make sure the parser does not get stuck when trying
321 // to parse an expression containing a syntax error.
322 // This usually results in OutOfMemoryError because the
323 // parser keeps filling up the error log.
324 // We need to make sure that we will always advance
325 // in the token stream.
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000326 parseExpression("f(1, ], 3)");
327 parseExpression("f(1, ), 3)");
328 parseExpression("[ ) for v in 3)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000329
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000330 assertContainsEvent(""); // "" matches any;
Ulf Adams89f012d2015-02-26 13:39:28 +0000331 // i.e. there were some events
332 }
333
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000334 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000335 public void testSecondaryLocation() {
336 String expr = "f(1 % 2)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000337 FuncallExpression call = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000338 Argument.Passed arg = call.getArguments().get(0);
Francois-Rene Rideauc673a822015-03-02 19:52:39 +0000339 assertThat(arg.getLocation().getEndOffset()).isLessThan(call.getLocation().getEndOffset());
Ulf Adams89f012d2015-02-26 13:39:28 +0000340 }
341
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000342 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000343 public void testPrimaryLocation() {
344 String expr = "f(1 + 2)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000345 FuncallExpression call = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000346 Argument.Passed arg = call.getArguments().get(0);
Francois-Rene Rideauc673a822015-03-02 19:52:39 +0000347 assertThat(arg.getLocation().getEndOffset()).isLessThan(call.getLocation().getEndOffset());
Ulf Adams89f012d2015-02-26 13:39:28 +0000348 }
349
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000350 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000351 public void testAssignLocation() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000352 List<Statement> statements = parseFile("a = b;c = d\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000353 Statement statement = statements.get(0);
354 assertEquals(5, statement.getLocation().getEndOffset());
355 }
356
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000357 @Test
Laurent Le Brunc9041bf2015-03-23 15:34:12 +0000358 public void testAssignKeyword() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000359 setFailFast(false);
360 parseExpression("with = 4");
361 assertContainsEvent("keyword 'with' not supported");
362 assertContainsEvent("syntax error at 'with': expected expression");
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000363 }
364
365 @Test
Laurent Le Brunee991a12015-06-16 10:56:46 +0000366 public void testBreak() {
367 setFailFast(false);
368 parseExpression("break");
369 assertContainsEvent("syntax error at 'break': expected expression");
370 }
371
372 @Test
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000373 public void testTry() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000374 setFailFast(false);
375 parseExpression("try: 1 + 1");
376 assertContainsEvent("'try' not supported, all exceptions are fatal");
377 assertContainsEvent("syntax error at 'try': expected expression");
Laurent Le Brunc9041bf2015-03-23 15:34:12 +0000378 }
379
380 @Test
Laurent Le Brun56093892015-03-20 13:01:58 +0000381 public void testTupleAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000382 List<Statement> statements = parseFile("list[0] = 5; dict['key'] = value\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000383 assertThat(statements).hasSize(2);
Laurent Le Brun56093892015-03-20 13:01:58 +0000384 assertThat(statements.get(0)).isInstanceOf(AssignmentStatement.class);
385 assertThat(statements.get(1)).isInstanceOf(AssignmentStatement.class);
386 }
387
388 @Test
389 public void testAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000390 List<Statement> statements = parseFile("a, b = 5\n");
Laurent Le Brun56093892015-03-20 13:01:58 +0000391 assertThat(statements).hasSize(1);
392 assertThat(statements.get(0)).isInstanceOf(AssignmentStatement.class);
393 AssignmentStatement assign = (AssignmentStatement) statements.get(0);
394 assertThat(assign.getLValue().getExpression()).isInstanceOf(ListLiteral.class);
Ulf Adams89f012d2015-02-26 13:39:28 +0000395 }
396
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000397 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000398 public void testInvalidAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000399 setFailFast(false);
400 parseExpression("1 + (b = c)");
401 assertContainsEvent("syntax error");
402 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000403 }
404
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000405 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000406 public void testAugmentedAssign() throws Exception {
407 assertEquals("[x = x + 1\n]", parseFile("x += 1").toString());
408 }
409
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000410 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000411 public void testPrettyPrintFunctions() throws Exception {
412 assertEquals("[x[1:3]\n]", parseFile("x[1:3]").toString());
413 assertEquals("[str[42]\n]", parseFile("str[42]").toString());
Francois-Rene Rideau9e3cc2e2015-05-18 18:35:36 +0000414 assertEquals("[ctx.new_file('hello')\n]", parseFile("ctx.new_file('hello')").toString());
415 assertEquals("[new_file('hello')\n]", parseFile("new_file('hello')").toString());
Ulf Adams89f012d2015-02-26 13:39:28 +0000416 }
417
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000418 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000419 public void testFuncallLocation() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000420 List<Statement> statements = parseFile("a(b);c = d\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000421 Statement statement = statements.get(0);
422 assertEquals(4, statement.getLocation().getEndOffset());
423 }
424
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000425 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000426 public void testSpecialFuncallLocation() throws Exception {
427 List<Statement> statements = parseFile("-x\n");
428 assertLocation(0, 3, statements.get(0).getLocation());
429
430 statements = parseFile("arr[15]\n");
431 assertLocation(0, 8, statements.get(0).getLocation());
432
433 statements = parseFile("str[1:12]\n");
434 assertLocation(0, 10, statements.get(0).getLocation());
435 }
436
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000437 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000438 public void testListPositions() throws Exception {
439 String expr = "[0,f(1),2]";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000440 ListLiteral list = (ListLiteral) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000441 assertEquals("[0,f(1),2]", getText(expr, list));
442 assertEquals("0", getText(expr, getElem(list, 0)));
443 assertEquals("f(1)", getText(expr, getElem(list, 1)));
444 assertEquals("2", getText(expr, getElem(list, 2)));
445 }
446
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000447 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000448 public void testDictPositions() throws Exception {
449 String expr = "{1:2,2:f(1),3:4}";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000450 DictionaryLiteral list = (DictionaryLiteral) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000451 assertEquals("{1:2,2:f(1),3:4}", getText(expr, list));
452 assertEquals("1:2", getText(expr, getElem(list, 0)));
453 assertEquals("2:f(1)", getText(expr, getElem(list, 1)));
454 assertEquals("3:4", getText(expr, getElem(list, 2)));
455 }
456
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000457 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000458 public void testArgumentPositions() throws Exception {
459 String stmt = "f(0,g(1,2),2)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000460 FuncallExpression f = (FuncallExpression) parseExpression(stmt);
Ulf Adams89f012d2015-02-26 13:39:28 +0000461 assertEquals(stmt, getText(stmt, f));
462 assertEquals("0", getText(stmt, getArg(f, 0)));
463 assertEquals("g(1,2)", getText(stmt, getArg(f, 1)));
464 assertEquals("2", getText(stmt, getArg(f, 2)));
465 }
466
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000467 @Test
Laurent Le Brund412c8f2015-06-16 11:12:54 +0000468 public void testForBreakContinue() throws Exception {
469 List<Statement> file = parseFileForSkylark(
470 "def foo():",
471 " for i in [1, 2]:",
472 " break",
473 " continue");
474 assertThat(file).hasSize(1);
475 List<Statement> body = ((FunctionDefStatement) file.get(0)).getStatements();
476 assertThat(body).hasSize(1);
477
478 List<Statement> loop = ((ForStatement) body.get(0)).block();
479 assertThat(loop).hasSize(2);
480
481 assertThat(loop.get(0)).isEqualTo(FlowStatement.BREAK);
482 assertLocation(34, 40, loop.get(0).getLocation());
483
484 assertThat(loop.get(1)).isEqualTo(FlowStatement.CONTINUE);
485 assertLocation(44, 52, loop.get(1).getLocation());
486 }
487
488 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000489 public void testListLiterals1() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000490 ListLiteral list = (ListLiteral) parseExpression("[0,1,2]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000491 assertFalse(list.isTuple());
492 assertThat(list.getElements()).hasSize(3);
493 assertFalse(list.isTuple());
494 for (int i = 0; i < 3; ++i) {
495 assertEquals(i, getIntElem(list, i));
496 }
497 }
498
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000499 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000500 public void testTupleLiterals2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000501 ListLiteral tuple = (ListLiteral) parseExpression("(0,1,2)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000502 assertTrue(tuple.isTuple());
503 assertThat(tuple.getElements()).hasSize(3);
504 assertTrue(tuple.isTuple());
505 for (int i = 0; i < 3; ++i) {
506 assertEquals(i, getIntElem(tuple, i));
507 }
508 }
509
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000510 @Test
Laurent Le Brun56093892015-03-20 13:01:58 +0000511 public void testTupleWithoutParens() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000512 ListLiteral tuple = (ListLiteral) parseExpression("0, 1, 2");
Laurent Le Brun56093892015-03-20 13:01:58 +0000513 assertTrue(tuple.isTuple());
514 assertThat(tuple.getElements()).hasSize(3);
515 assertTrue(tuple.isTuple());
516 for (int i = 0; i < 3; ++i) {
517 assertEquals(i, getIntElem(tuple, i));
518 }
519 }
520
521 @Test
522 public void testTupleWithoutParensWithTrailingComma() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000523 ListLiteral tuple = (ListLiteral) parseExpression("0, 1, 2, 3,");
Laurent Le Brun56093892015-03-20 13:01:58 +0000524 assertTrue(tuple.isTuple());
525 assertThat(tuple.getElements()).hasSize(4);
526 assertTrue(tuple.isTuple());
527 for (int i = 0; i < 4; ++i) {
528 assertEquals(i, getIntElem(tuple, i));
529 }
530 }
531
532 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000533 public void testTupleLiterals3() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000534 ListLiteral emptyTuple = (ListLiteral) parseExpression("()");
Ulf Adams89f012d2015-02-26 13:39:28 +0000535 assertTrue(emptyTuple.isTuple());
536 assertThat(emptyTuple.getElements()).isEmpty();
537 }
538
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000539 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000540 public void testTupleLiterals4() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000541 ListLiteral singletonTuple = (ListLiteral) parseExpression("(42,)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000542 assertTrue(singletonTuple.isTuple());
543 assertThat(singletonTuple.getElements()).hasSize(1);
544 assertEquals(42, getIntElem(singletonTuple, 0));
545 }
546
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000547 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000548 public void testTupleLiterals5() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000549 IntegerLiteral intLit = (IntegerLiteral) parseExpression("(42)"); // not a tuple!
Ulf Adams89f012d2015-02-26 13:39:28 +0000550 assertEquals(42, (int) intLit.getValue());
551 }
552
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000553 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000554 public void testListLiterals6() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000555 ListLiteral emptyList = (ListLiteral) parseExpression("[]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000556 assertFalse(emptyList.isTuple());
557 assertThat(emptyList.getElements()).isEmpty();
558 }
559
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000560 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000561 public void testListLiterals7() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000562 ListLiteral singletonList = (ListLiteral) parseExpression("[42,]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000563 assertFalse(singletonList.isTuple());
564 assertThat(singletonList.getElements()).hasSize(1);
565 assertEquals(42, getIntElem(singletonList, 0));
566 }
567
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000568 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000569 public void testListLiterals8() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000570 ListLiteral singletonList = (ListLiteral) parseExpression("[42]"); // a singleton
Ulf Adams89f012d2015-02-26 13:39:28 +0000571 assertFalse(singletonList.isTuple());
572 assertThat(singletonList.getElements()).hasSize(1);
573 assertEquals(42, getIntElem(singletonList, 0));
574 }
575
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000576 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000577 public void testDictionaryLiterals() throws Exception {
578 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000579 (DictionaryLiteral) parseExpression("{1:42}"); // a singleton dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000580 assertThat(dictionaryList.getEntries()).hasSize(1);
581 DictionaryEntryLiteral tuple = getElem(dictionaryList, 0);
582 assertEquals(1, getIntElem(tuple, true));
583 assertEquals(42, getIntElem(tuple, false));
584 }
585
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000586 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000587 public void testDictionaryLiterals1() throws Exception {
588 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000589 (DictionaryLiteral) parseExpression("{}"); // an empty dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000590 assertThat(dictionaryList.getEntries()).isEmpty();
591 }
592
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000593 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000594 public void testDictionaryLiterals2() throws Exception {
595 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000596 (DictionaryLiteral) parseExpression("{1:42,}"); // a singleton dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000597 assertThat(dictionaryList.getEntries()).hasSize(1);
598 DictionaryEntryLiteral tuple = getElem(dictionaryList, 0);
599 assertEquals(1, getIntElem(tuple, true));
600 assertEquals(42, getIntElem(tuple, false));
601 }
602
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000603 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000604 public void testDictionaryLiterals3() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000605 DictionaryLiteral dictionaryList = (DictionaryLiteral) parseExpression("{1:42,2:43,3:44}");
Ulf Adams89f012d2015-02-26 13:39:28 +0000606 assertThat(dictionaryList.getEntries()).hasSize(3);
607 for (int i = 0; i < 3; i++) {
608 DictionaryEntryLiteral tuple = getElem(dictionaryList, i);
609 assertEquals(i + 1, getIntElem(tuple, true));
610 assertEquals(i + 42, getIntElem(tuple, false));
611 }
612 }
613
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000614 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000615 public void testListLiterals9() throws Exception {
616 ListLiteral singletonList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000617 (ListLiteral) parseExpression("[ abi + opt_level + \'/include\' ]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000618 assertFalse(singletonList.isTuple());
619 assertThat(singletonList.getElements()).hasSize(1);
620 }
621
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000622 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000623 public void testListComprehensionSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000624 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000625
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000626 parseExpression("[x for");
627 assertContainsEvent("syntax error at 'newline'");
628 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000629
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000630 parseExpression("[x for x");
631 assertContainsEvent("syntax error at 'newline'");
632 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000633
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000634 parseExpression("[x for x in");
635 assertContainsEvent("syntax error at 'newline'");
636 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000637
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000638 parseExpression("[x for x in []");
639 assertContainsEvent("syntax error at 'newline'");
640 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000641
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000642 parseExpression("[x for x for y in ['a']]");
643 assertContainsEvent("syntax error at 'for'");
644 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000645 }
646
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000647 @Test
Laurent Le Brun52021662015-05-18 09:28:26 +0000648 public void testListComprehensionEmptyList() throws Exception {
649 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
650 "['foo/%s.java' % x for x in []]")).getClauses();
651 assertThat(clauses).hasSize(1);
652 assertThat(clauses.get(0).getExpression().toString()).isEqualTo("[]");
653 assertThat(clauses.get(0).getLValue().getExpression().toString()).isEqualTo("x");
654 }
655
656 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000657 public void testListComprehension() throws Exception {
Laurent Le Brun52021662015-05-18 09:28:26 +0000658 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
659 "['foo/%s.java' % x for x in ['bar', 'wiz', 'quux']]")).getClauses();
660 assertThat(clauses).hasSize(1);
661 assertThat(clauses.get(0).getLValue().getExpression().toString()).isEqualTo("x");
662 assertThat(clauses.get(0).getExpression()).isInstanceOf(ListLiteral.class);
663 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000664
Laurent Le Brun52021662015-05-18 09:28:26 +0000665 @Test
666 public void testForForListComprehension() throws Exception {
667 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
668 "['%s/%s.java' % (x, y) for x in ['foo', 'bar'] for y in list]")).getClauses();
669 assertThat(clauses).hasSize(2);
670 assertThat(clauses.get(0).getLValue().getExpression().toString()).isEqualTo("x");
671 assertThat(clauses.get(0).getExpression()).isInstanceOf(ListLiteral.class);
672 assertThat(clauses.get(1).getLValue().getExpression().toString()).isEqualTo("y");
Florian Weikert6f864c32015-07-23 11:26:39 +0000673 assertThat(clauses.get(1).getExpression()).isInstanceOf(Identifier.class);
Ulf Adams89f012d2015-02-26 13:39:28 +0000674 }
675
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000676 @Test
Laurent Le Brun9060e162015-04-02 10:07:28 +0000677 public void testParserRecovery() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000678 setFailFast(false);
679 List<Statement> statements = parseFileForSkylark(
Laurent Le Brun9060e162015-04-02 10:07:28 +0000680 "def foo():",
Laurent Le Brune3f4ed72015-05-08 14:47:26 +0000681 " a = 2 for 4", // parse error
Laurent Le Brun9060e162015-04-02 10:07:28 +0000682 " b = [3, 4]",
683 "",
684 "d = 4 ada", // parse error
685 "",
686 "def bar():",
687 " a = [3, 4]",
688 " b = 2 + + 5", // parse error
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000689 "");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000690
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000691 assertThat(getEventCollector()).hasSize(3);
Laurent Le Brune3f4ed72015-05-08 14:47:26 +0000692 assertContainsEvent("syntax error at 'for': expected newline");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000693 assertContainsEvent("syntax error at 'ada': expected newline");
694 assertContainsEvent("syntax error at '+': expected expression");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000695 assertThat(statements).hasSize(3);
696 }
697
698 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000699 public void testParserContainsErrorsIfSyntaxException() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000700 setFailFast(false);
701 parseExpression("'foo' %%");
702 assertContainsEvent("syntax error at '%'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000703 }
704
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000705 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000706 public void testParserDoesNotContainErrorsIfSuccess() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000707 parseExpression("'foo'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000708 }
709
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000710 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000711 public void testParserContainsErrors() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000712 setFailFast(false);
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +0000713 parseFile("+");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000714 assertContainsEvent("syntax error at '+'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000715 }
716
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000717 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000718 public void testSemicolonAndNewline() throws Exception {
719 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000720 "foo='bar'; foo(bar)",
721 "",
722 "foo='bar'; foo(bar)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000723 assertThat(stmts).hasSize(4);
724 }
725
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000726 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000727 public void testSemicolonAndNewline2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000728 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000729 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000730 "foo='foo' error(bar)",
731 "",
732 "");
733 assertContainsEvent("syntax error at 'error'");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000734 assertThat(stmts).hasSize(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000735 }
736
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000737 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000738 public void testExprAsStatement() throws Exception {
739 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000740 "li = []",
741 "li.append('a.c')",
742 "\"\"\" string comment \"\"\"",
743 "foo(bar)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000744 assertThat(stmts).hasSize(4);
745 }
746
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000747 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000748 public void testParseBuildFileWithSingeRule() throws Exception {
749 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000750 "genrule(name = 'foo',",
751 " srcs = ['input.csv'],",
752 " outs = [ 'result.txt',",
753 " 'result.log'],",
754 " cmd = 'touch result.txt result.log')",
755 "");
Ulf Adams89f012d2015-02-26 13:39:28 +0000756 assertThat(stmts).hasSize(1);
757 }
758
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000759 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000760 public void testParseBuildFileWithMultipleRules() throws Exception {
761 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000762 "genrule(name = 'foo',",
763 " srcs = ['input.csv'],",
764 " outs = [ 'result.txt',",
765 " 'result.log'],",
766 " cmd = 'touch result.txt result.log')",
767 "",
768 "genrule(name = 'bar',",
769 " srcs = ['input.csv'],",
770 " outs = [ 'graph.svg'],",
771 " cmd = 'touch graph.svg')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000772 assertThat(stmts).hasSize(2);
773 }
774
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000775 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000776 public void testParseBuildFileWithComments() throws Exception {
777 Parser.ParseResult result = parseFileWithComments(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000778 "# Test BUILD file",
779 "# with multi-line comment",
780 "",
781 "genrule(name = 'foo',",
782 " srcs = ['input.csv'],",
783 " outs = [ 'result.txt',",
784 " 'result.log'],",
785 " cmd = 'touch result.txt result.log')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000786 assertThat(result.statements).hasSize(1);
787 assertThat(result.comments).hasSize(2);
788 }
789
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000790 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000791 public void testParseBuildFileWithManyComments() throws Exception {
792 Parser.ParseResult result = parseFileWithComments(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000793 "# 1",
794 "# 2",
795 "",
796 "# 4 ",
797 "# 5",
798 "#", // 6 - find empty comment for syntax highlighting
799 "# 7 ",
800 "# 8",
801 "genrule(name = 'foo',",
802 " srcs = ['input.csv'],",
803 " # 11",
804 " outs = [ 'result.txt',",
805 " 'result.log'], # 13",
806 " cmd = 'touch result.txt result.log')",
807 "# 15");
Ulf Adams89f012d2015-02-26 13:39:28 +0000808 assertThat(result.statements).hasSize(1); // Single genrule
809 StringBuilder commentLines = new StringBuilder();
810 for (Comment comment : result.comments) {
811 // Comments start and end on the same line
812 assertEquals(comment.getLocation().getStartLineAndColumn().getLine() + " ends on "
813 + comment.getLocation().getEndLineAndColumn().getLine(),
814 comment.getLocation().getStartLineAndColumn().getLine(),
815 comment.getLocation().getEndLineAndColumn().getLine());
816 commentLines.append('(');
817 commentLines.append(comment.getLocation().getStartLineAndColumn().getLine());
818 commentLines.append(',');
819 commentLines.append(comment.getLocation().getStartLineAndColumn().getColumn());
820 commentLines.append(") ");
821 }
822 assertWithMessage("Found: " + commentLines)
823 .that(result.comments.size()).isEqualTo(10); // One per '#'
824 }
825
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000826 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000827 public void testMissingComma() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000828 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000829 // Regression test.
830 // Note: missing comma after name='foo'
831 parseFile("genrule(name = 'foo'\n"
832 + " srcs = ['in'])");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000833 assertContainsEvent("syntax error at 'srcs'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000834 }
835
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000836 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000837 public void testDoubleSemicolon() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000838 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000839 // Regression test.
840 parseFile("x = 1; ; x = 2;");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000841 assertContainsEvent("syntax error at ';'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000842 }
843
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000844 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000845 public void testFunctionDefinitionErrorRecovery() throws Exception {
846 // Parser skips over entire function definitions, and reports a meaningful
847 // error.
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000848 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000849 List<Statement> stmts = parseFile(
850 "x = 1;\n"
851 + "def foo(x, y, **z):\n"
852 + " # a comment\n"
853 + " x = 2\n"
854 + " foo(bar)\n"
855 + " return z\n"
856 + "x = 3");
857 assertThat(stmts).hasSize(2);
858 }
859
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000860 @Test
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000861 public void testFunctionDefinitionIgnoredEvenWithUnsupportedKeyword() throws Exception {
862 // Parser skips over entire function definitions without reporting error,
863 // when parsePython is set to true.
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000864 List<Statement> stmts = parseFileWithPython(
865 "x = 1;",
866 "def foo(x, y, **z):",
867 " try:",
868 " x = 2",
869 " with: pass",
870 " return 2",
871 "x = 3");
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000872 assertThat(stmts).hasSize(2);
873 }
874
875 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000876 public void testFunctionDefinitionIgnored() throws Exception {
877 // Parser skips over entire function definitions without reporting error,
878 // when parsePython is set to true.
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000879 List<Statement> stmts = parseFileWithPython(
880 "x = 1;",
881 "def foo(x, y, **z):",
882 " # a comment",
883 " if true:",
884 " x = 2",
885 " foo(bar)",
886 " return z",
887 "x = 3");
Ulf Adams89f012d2015-02-26 13:39:28 +0000888 assertThat(stmts).hasSize(2);
889
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000890 stmts = parseFileWithPython(
891 "x = 1;",
892 "def foo(x, y, **z): return x",
893 "x = 3");
Ulf Adams89f012d2015-02-26 13:39:28 +0000894 assertThat(stmts).hasSize(2);
895 }
896
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000897 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000898 public void testMissingBlock() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000899 setFailFast(false);
900 List<Statement> stmts = parseFileWithPython(
901 "x = 1;",
902 "def foo(x):",
903 "x = 2;\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000904 assertThat(stmts).hasSize(2);
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000905 assertContainsEvent("expected an indented block");
Ulf Adams89f012d2015-02-26 13:39:28 +0000906 }
907
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000908 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000909 public void testInvalidDef() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000910 setFailFast(false);
911 parseFileWithPython(
912 "x = 1;",
913 "def foo(x)",
914 "x = 2;\n");
915 assertContainsEvent("syntax error at 'EOF'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000916 }
917
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000918 @Test
Laurent Le Brun5f674452015-03-17 19:29:13 +0000919 public void testDefSingleLine() throws Exception {
920 List<Statement> statements = parseFileForSkylark(
921 "def foo(): x = 1; y = 2\n");
922 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
923 assertThat(stmt.getStatements()).hasSize(2);
924 }
925
926 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000927 public void testSkipIfBlock() throws Exception {
928 // Skip over 'if' blocks, when parsePython is set
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000929 List<Statement> stmts = parseFileWithPython(
930 "x = 1;",
931 "if x == 1:",
932 " foo(x)",
933 "else:",
934 " bar(x)",
935 "x = 3;\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000936 assertThat(stmts).hasSize(2);
937 }
938
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000939 @Test
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000940 public void testPass() throws Exception {
941 List<Statement> statements = parseFileForSkylark("pass\n");
942 assertThat(statements).isEmpty();
943 }
944
945 @Test
946 public void testForPass() throws Exception {
947 List<Statement> statements = parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000948 "def foo():",
949 " pass\n");
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000950
951 assertThat(statements).hasSize(1);
952 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
953 assertThat(stmt.getStatements()).isEmpty();
954 }
955
956 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000957 public void testSkipIfBlockFail() throws Exception {
958 // Do not parse 'if' blocks, when parsePython is not set
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000959 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000960 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000961 "x = 1;",
962 "if x == 1:",
963 " x = 2",
964 "x = 3;\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000965 assertThat(stmts).hasSize(2);
Laurent Le Brunb13a4382015-06-30 14:20:45 +0000966 assertContainsEvent("This is not supported in BUILD files");
Ulf Adams89f012d2015-02-26 13:39:28 +0000967 }
968
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000969 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000970 public void testForLoopMultipleVariables() throws Exception {
Laurent Le Brun185392d2015-03-20 14:41:25 +0000971 List<Statement> stmts1 = parseFile("[ i for i, j, k in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000972 assertThat(stmts1).hasSize(1);
973
Laurent Le Brun185392d2015-03-20 14:41:25 +0000974 List<Statement> stmts2 = parseFile("[ i for i, j in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000975 assertThat(stmts2).hasSize(1);
976
Laurent Le Brun185392d2015-03-20 14:41:25 +0000977 List<Statement> stmts3 = parseFile("[ i for (i, j, k) in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000978 assertThat(stmts3).hasSize(1);
979 }
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000980
Googlercc0d9952015-08-10 12:01:34 +0000981 @Test
982 public void testReturnNone() throws Exception {
983 List<Statement> defNone = parseFileForSkylark("def foo():", " return None\n");
984 assertThat(defNone).hasSize(1);
985
986 List<Statement> bodyNone = ((FunctionDefStatement) defNone.get(0)).getStatements();
987 assertThat(bodyNone).hasSize(1);
988
989 ReturnStatement returnNone = (ReturnStatement) bodyNone.get(0);
990 assertEquals("None", ((Identifier) returnNone.getReturnExpression()).getName());
991
992 int i = 0;
993 for (String end : new String[]{";", "\n"}) {
994 List<Statement> defNoExpr = parseFileForSkylark("def bar" + i + "():", " return" + end);
995 i++;
996 assertThat(defNoExpr).hasSize(1);
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000997
Googlercc0d9952015-08-10 12:01:34 +0000998 List<Statement> bodyNoExpr = ((FunctionDefStatement) defNoExpr.get(0)).getStatements();
999 assertThat(bodyNoExpr).hasSize(1);
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001000
Googlercc0d9952015-08-10 12:01:34 +00001001 ReturnStatement returnNoExpr = (ReturnStatement) bodyNoExpr.get(0);
1002 Identifier none = (Identifier) returnNoExpr.getReturnExpression();
1003 assertEquals("None", none.getName());
1004 assertLocation(
1005 returnNoExpr.getLocation().getStartOffset(),
1006 returnNoExpr.getLocation().getEndOffset(),
1007 none.getLocation());
1008 }
1009 }
Ulf Adams89f012d2015-02-26 13:39:28 +00001010
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001011 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001012 public void testForLoopBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001013 setFailFast(false);
Laurent Le Brun185392d2015-03-20 14:41:25 +00001014 parseFile("[1 for (a, b, c in var]\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001015 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001016 }
1017
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001018 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001019 public void testForLoopBadSyntax2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001020 setFailFast(false);
Laurent Le Brun185392d2015-03-20 14:41:25 +00001021 parseFile("[1 for in var]\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001022 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001023 }
1024
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001025 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001026 public void testFunCallBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001027 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001028 parseFile("f(1,\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001029 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001030 }
1031
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001032 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001033 public void testFunCallBadSyntax2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001034 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001035 parseFile("f(1, 5, ,)\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001036 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001037 }
1038
Florian Weikert308c0bf2015-07-10 10:46:56 +00001039 private static final String DOUBLE_SLASH_LOAD = "load('//foo/bar/file', 'test')\n";
1040 private static final String DOUBLE_SLASH_ERROR =
1041 "First argument of load() is a path, not a label. It should start with a "
1042 + "single slash if it is an absolute path.";
1043
1044 @Test
1045 public void testLoadDoubleSlashBuild() throws Exception {
1046 setFailFast(false);
1047 parseFile(DOUBLE_SLASH_LOAD);
1048 assertContainsEvent(DOUBLE_SLASH_ERROR);
1049 }
1050
1051 @Test
1052 public void testLoadDoubleSlashSkylark() throws Exception {
1053 setFailFast(false);
1054 parseFileForSkylark(DOUBLE_SLASH_LOAD);
1055 assertContainsEvent(DOUBLE_SLASH_ERROR);
1056 }
1057
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001058 @Test
Laurent Le Brun73a98492015-03-17 15:46:19 +00001059 public void testLoadNoSymbol() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001060 setFailFast(false);
Laurent Le Brun73a98492015-03-17 15:46:19 +00001061 parseFileForSkylark("load('/foo/bar/file')\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001062 assertContainsEvent("syntax error");
Laurent Le Brun73a98492015-03-17 15:46:19 +00001063 }
1064
1065 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001066 public void testLoadOneSymbol() throws Exception {
1067 List<Statement> statements = parseFileForSkylark(
1068 "load('/foo/bar/file', 'fun_test')\n");
1069 LoadStatement stmt = (LoadStatement) statements.get(0);
1070 assertEquals("/foo/bar/file.bzl", stmt.getImportPath().toString());
1071 assertThat(stmt.getSymbols()).hasSize(1);
1072 }
1073
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001074 @Test
Laurent Le Brun59f587a2015-03-16 14:51:36 +00001075 public void testLoadOneSymbolWithTrailingComma() throws Exception {
1076 List<Statement> statements = parseFileForSkylark(
1077 "load('/foo/bar/file', 'fun_test',)\n");
1078 LoadStatement stmt = (LoadStatement) statements.get(0);
1079 assertEquals("/foo/bar/file.bzl", stmt.getImportPath().toString());
1080 assertThat(stmt.getSymbols()).hasSize(1);
1081 }
1082
1083 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001084 public void testLoadMultipleSymbols() throws Exception {
1085 List<Statement> statements = parseFileForSkylark(
1086 "load('file', 'foo', 'bar')\n");
1087 LoadStatement stmt = (LoadStatement) statements.get(0);
1088 assertEquals("file.bzl", stmt.getImportPath().toString());
1089 assertThat(stmt.getSymbols()).hasSize(2);
1090 }
1091
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001092 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001093 public void testLoadSyntaxError() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001094 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001095 parseFileForSkylark("load(non_quoted, 'a')\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001096 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001097 }
1098
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001099 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001100 public void testLoadSyntaxError2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001101 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001102 parseFileForSkylark("load('non_quoted', a)\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001103 assertContainsEvent("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001104 }
1105
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001106 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001107 public void testLoadNotAtTopLevel() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001108 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001109 parseFileForSkylark("if 1: load(8)\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001110 assertContainsEvent("function 'load' does not exist");
Ulf Adams89f012d2015-02-26 13:39:28 +00001111 }
1112
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001113 @Test
Florian Weikert9d659ad2015-07-23 14:44:36 +00001114 public void testLoadAlias() throws Exception {
1115 runLoadAliasTestForSymbols("my_alias = 'lawl'", "my_alias");
1116 }
1117
1118 @Test
1119 public void testLoadAliasMultiple() throws Exception {
1120 runLoadAliasTestForSymbols(
1121 "my_alias = 'lawl', 'lol', next_alias = 'rofl'", "my_alias", "lol", "next_alias");
1122 }
1123
1124 private void runLoadAliasTestForSymbols(String loadSymbolString, String... expectedSymbols) {
1125 List<Statement> statements =
1126 parseFileForSkylark(String.format("load('/foo/bar/file', %s)\n", loadSymbolString));
1127 LoadStatement stmt = (LoadStatement) statements.get(0);
1128 ImmutableList<Identifier> actualSymbols = stmt.getSymbols();
1129
1130 assertThat(actualSymbols).hasSize(expectedSymbols.length);
1131
1132 List<String> actualSymbolNames = new LinkedList<>();
1133
1134 for (Identifier identifier : actualSymbols) {
1135 actualSymbolNames.add(identifier.getName());
1136 }
1137
1138 assertThat(actualSymbolNames).containsExactly((Object[]) expectedSymbols);
1139 }
1140
1141 @Test
1142 public void testLoadAliasSyntaxError() throws Exception {
1143 setFailFast(false);
1144 parseFileForSkylark("load('/foo', test1 = )\n");
1145 assertContainsEvent("syntax error at ')': expected string");
1146
1147 parseFileForSkylark("load('/foo', test2 = 1)\n");
1148 assertContainsEvent("syntax error at '1': expected string");
1149
1150 parseFileForSkylark("load('/foo', test3 = old)\n");
1151 assertContainsEvent("syntax error at 'old': expected string");
1152 }
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001153
Florian Weikert9d659ad2015-07-23 14:44:36 +00001154 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001155 public void testParseErrorNotComparison() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001156 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001157 parseFile("2 < not 3");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001158 assertContainsEvent("syntax error at 'not'");
Ulf Adams89f012d2015-02-26 13:39:28 +00001159 }
1160
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001161 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001162 public void testNotWithArithmeticOperatorsBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001163 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001164 parseFile("0 + not 0");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001165 assertContainsEvent("syntax error at 'not'");
Ulf Adams89f012d2015-02-26 13:39:28 +00001166 }
1167
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001168 @Test
Laurent Le Brunb3266382015-05-27 16:14:43 +00001169 public void testKwargsForbidden() throws Exception {
1170 setFailFast(false);
1171 parseFile("func(**dict)");
1172 assertContainsEvent("**kwargs arguments are not allowed in BUILD files");
1173 }
1174
1175 @Test
1176 public void testArgsForbidden() throws Exception {
1177 setFailFast(false);
1178 parseFile("func(*array)");
1179 assertContainsEvent("*args arguments are not allowed in BUILD files");
1180 }
1181
1182 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001183 public void testOptionalArgBeforeMandatoryArgInFuncDef() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001184 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001185 parseFileForSkylark("def func(a, b = 'a', c):\n return 0\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001186 assertContainsEvent(
Ulf Adams89f012d2015-02-26 13:39:28 +00001187 "a mandatory positional parameter must not follow an optional parameter");
1188 }
1189
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001190 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001191 public void testKwargBeforePositionalArg() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001192 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001193 parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001194 "def func(a, b): return a + b",
1195 "func(**{'b': 1}, 'a')");
1196 assertContainsEvent("unexpected tokens after kwarg");
Ulf Adams89f012d2015-02-26 13:39:28 +00001197 }
1198
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001199 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001200 public void testDuplicateKwarg() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001201 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001202 parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001203 "def func(a, b): return a + b",
1204 "func(**{'b': 1}, **{'a': 2})");
1205 assertContainsEvent("unexpected tokens after kwarg");
Ulf Adams89f012d2015-02-26 13:39:28 +00001206 }
1207
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001208 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001209 public void testUnnamedStar() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001210 setFailFast(false);
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001211 List<Statement> statements = parseFileForSkylark(
1212 "def func(a, b1=2, b2=3, *, c1, d=4, c2): return a + b1 + b2 + c1 + c2 + d\n");
1213 assertThat(statements).hasSize(1);
1214 assertThat(statements.get(0)).isInstanceOf(FunctionDefStatement.class);
1215 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
Laurent Le Brun4baefdc2015-09-04 11:27:46 +00001216 FunctionSignature sig = stmt.getSignature().getSignature();
Francois-Rene Rideau012f7892015-03-31 17:27:01 +00001217 // Note the reordering of optional named-only at the end.
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001218 assertThat(sig.getNames()).isEqualTo(ImmutableList.<String>of(
Francois-Rene Rideau012f7892015-03-31 17:27:01 +00001219 "a", "b1", "b2", "c1", "c2", "d"));
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001220 FunctionSignature.Shape shape = sig.getShape();
1221 assertThat(shape.getMandatoryPositionals()).isEqualTo(1);
1222 assertThat(shape.getOptionalPositionals()).isEqualTo(2);
1223 assertThat(shape.getMandatoryNamedOnly()).isEqualTo(2);
1224 assertThat(shape.getOptionalNamedOnly()).isEqualTo(1);
Ulf Adams89f012d2015-02-26 13:39:28 +00001225 }
1226
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001227 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001228 public void testTopLevelForFails() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001229 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001230 parseFileForSkylark("for i in []: 0\n");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001231 assertContainsEvent(
Ulf Adams89f012d2015-02-26 13:39:28 +00001232 "for loops are not allowed on top-level. Put it into a function");
1233 }
1234
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001235 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001236 public void testNestedFunctionFails() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001237 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001238 parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001239 "def func(a):",
1240 " def bar(): return 0",
1241 " return bar()",
1242 "");
1243 assertContainsEvent(
Ulf Adams89f012d2015-02-26 13:39:28 +00001244 "nested functions are not allowed. Move the function to top-level");
1245 }
1246
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001247 @Test
Laurent Le Brun3bc8e9a2015-09-10 11:00:37 +00001248 public void testElseWithoutIf() throws Exception {
1249 setFailFast(false);
1250 parseFileForSkylark(
1251 "def func(a):",
1252 // no if
1253 " else: return a");
1254 assertContainsEvent("syntax error at 'else'");
1255 }
Ulf Adams89f012d2015-02-26 13:39:28 +00001256}