blob: 87ba491df9d1bfe83ef051f0c99e22b75e771d63 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2015 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;
Benjamin Petersonbf1db782018-08-08 10:03:22 -070017import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
cparsons979195e2018-04-09 15:43:22 -070018import static java.util.stream.Collectors.joining;
Ulf Adams89f012d2015-02-26 13:39:28 +000019
20import com.google.common.collect.ImmutableCollection;
21import com.google.common.collect.ImmutableList;
22import com.google.common.collect.ImmutableMap;
cparsons645a35e2018-10-01 13:03:23 -070023import com.google.devtools.build.lib.analysis.test.AnalysisFailure;
24import com.google.devtools.build.lib.analysis.test.AnalysisFailureInfo;
25import com.google.devtools.build.lib.cmdline.Label;
Ulf Adams89f012d2015-02-26 13:39:28 +000026import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
dslomov423dccc2017-04-11 12:18:09 +000027import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
cparsonse70aafe2018-02-28 12:16:38 -080028import com.google.devtools.build.lib.events.Location;
dslomovf1296572017-08-22 16:29:06 +020029import com.google.devtools.build.lib.packages.NativeInfo;
dslomovde965ac2017-07-31 21:07:51 +020030import com.google.devtools.build.lib.packages.NativeProvider;
cparsons0c5c1c62018-05-24 10:37:03 -070031import com.google.devtools.build.lib.packages.StructProvider;
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +000032import com.google.devtools.build.lib.skylarkinterface.Param;
Dmitry Lomovd22e1de2017-09-25 08:53:50 -040033import com.google.devtools.build.lib.skylarkinterface.ParamType;
John Field585d1a02015-12-16 16:03:52 +000034import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
35import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
Vladimir Moskvaa5b16742016-10-31 14:09:41 +000036import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
dslomov423dccc2017-04-11 12:18:09 +000037import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
cparsonsb380dc92018-12-05 13:57:39 -080038import com.google.devtools.build.lib.skylarkinterface.StarlarkContext;
Francois-Rene Rideauef7a8a52016-01-29 17:37:48 +000039import com.google.devtools.build.lib.syntax.SkylarkList.MutableList;
laurentlb6659b4c2019-02-18 07:23:36 -080040import com.google.devtools.build.lib.syntax.StarlarkSemantics.FlagIdentifier;
Florian Weikert28da3652015-07-01 14:52:30 +000041import com.google.devtools.build.lib.testutil.TestMode;
cparsonsaaab11f2018-01-31 11:00:11 -080042import java.util.List;
43import java.util.Map;
Han-Wen Nienhuys33ce2112015-09-25 14:25:38 +000044import org.junit.Before;
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000045import org.junit.Test;
46import org.junit.runner.RunWith;
47import org.junit.runners.JUnit4;
48
Ulf Adams89f012d2015-02-26 13:39:28 +000049/**
50 * Evaluation tests with Skylark Environment.
51 */
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000052@RunWith(JUnit4.class)
Ulf Adams89f012d2015-02-26 13:39:28 +000053public class SkylarkEvaluationTest extends EvaluationTest {
Florian Weikertb4c59042015-12-01 10:47:18 +000054
Han-Wen Nienhuys33ce2112015-09-25 14:25:38 +000055 @Before
Florian Weikertb4c59042015-12-01 10:47:18 +000056 public final void setup() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +000057 setMode(TestMode.SKYLARK);
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000058 }
59
Florian Weikert28da3652015-07-01 14:52:30 +000060 /**
61 * Creates an instance of {@code SkylarkTest} in order to run the tests from the base class in a
62 * Skylark context
63 */
64 @Override
vladmos6ff634d2017-07-05 10:25:01 -040065 protected ModalTestCase newTest(String... skylarkOptions) {
66 return new SkylarkTest(skylarkOptions);
Florian Weikert28da3652015-07-01 14:52:30 +000067 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +000068
dslomov423dccc2017-04-11 12:18:09 +000069 @Immutable
Francois-Rene Rideau6c10eac2015-09-17 19:17:20 +000070 static class Bad {
71 Bad () {
72 }
73 }
74
Vladimir Moskvaa5b16742016-10-31 14:09:41 +000075 @SkylarkSignature(name = "foobar", returnType = String.class, documented = false)
76 static BuiltinFunction foobar = new BuiltinFunction("foobar") {
77 public String invoke() throws EvalException {
78 return "foobar";
79 }
80 };
81
Benjamin Petersonbf1db782018-08-08 10:03:22 -070082 @SkylarkSignature(
83 name = "interrupted_function",
84 returnType = Runtime.NoneType.class,
85 documented = false)
86 static BuiltinFunction interruptedFunction =
87 new BuiltinFunction("interrupted_function") {
88 public Runtime.NoneType invoke() throws InterruptedException {
89 throw new InterruptedException();
90 }
91 };
92
Ulf Adams89f012d2015-02-26 13:39:28 +000093 @SkylarkModule(name = "Mock", doc = "")
cparsons6c1c0662018-02-05 02:01:28 -080094 static class NativeInfoMock extends NativeInfo {
95
96 private static final NativeProvider<NativeInfoMock> CONSTRUCTOR =
97 new NativeProvider<NativeInfoMock>(NativeInfoMock.class, "native_info_mock") {};
98
99 public NativeInfoMock() {
100 super(CONSTRUCTOR);
101 }
102
cparsons7f475d72018-03-30 13:54:46 -0700103 @SkylarkCallable(name = "callable_string", documented = false, structField = false)
cparsons6c1c0662018-02-05 02:01:28 -0800104 public String callableString() {
105 return "a";
106 }
107
cparsons7f475d72018-03-30 13:54:46 -0700108 @SkylarkCallable(name = "struct_field_string", documented = false, structField = true)
cparsons6c1c0662018-02-05 02:01:28 -0800109 public String structFieldString() {
110 return "a";
111 }
112
cparsons7f475d72018-03-30 13:54:46 -0700113 @SkylarkCallable(name = "struct_field_callable", documented = false, structField = true)
cparsons6c1c0662018-02-05 02:01:28 -0800114 public BuiltinFunction structFieldCallable() {
115 return foobar;
116 }
117
118 @SkylarkCallable(
119 name = "struct_field_none",
cparsons7f475d72018-03-30 13:54:46 -0700120 documented = false,
cparsons6c1c0662018-02-05 02:01:28 -0800121 structField = true,
122 allowReturnNones = true
123 )
124 public String structFieldNone() {
125 return null;
126 }
127 }
128
129 @SkylarkModule(name = "Mock", doc = "")
Ulf Adams89f012d2015-02-26 13:39:28 +0000130 static class Mock {
cparsons6c197202018-10-31 15:49:23 -0700131 @SkylarkCallable(
132 name = "MockFn",
133 selfCall = true,
134 documented = false,
cparsons0e866862018-04-24 08:07:02 -0700135 parameters = {
cparsons6c197202018-10-31 15:49:23 -0700136 @Param(name = "pos", positional = true, type = String.class),
137 })
138 public String selfCall(String myName) {
cparsons0e866862018-04-24 08:07:02 -0700139 return "I'm a mock named " + myName;
140 }
141
cparsons6c197202018-10-31 15:49:23 -0700142 @SkylarkCallable(
143 name = "value_of",
144 parameters = {@Param(name = "str", type = String.class)},
cparsonse661f882018-06-28 10:12:05 -0700145 documented = false)
cparsons6c197202018-10-31 15:49:23 -0700146 public Integer valueOf(String str) {
Ulf Adams89f012d2015-02-26 13:39:28 +0000147 return Integer.valueOf(str);
148 }
cparsonse661f882018-06-28 10:12:05 -0700149 @SkylarkCallable(name = "is_empty",
150 parameters = { @Param(name = "str", type = String.class) },
151 documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000152 public Boolean isEmpty(String str) {
153 return str.isEmpty();
154 }
155 public void value() {}
cparsons88d1cae2018-06-22 15:12:00 -0700156 @SkylarkCallable(name = "return_bad", documented = false)
Francois-Rene Rideau6c10eac2015-09-17 19:17:20 +0000157 public Bad returnBad() {
158 return new Bad();
Ulf Adams89f012d2015-02-26 13:39:28 +0000159 }
cparsons7f475d72018-03-30 13:54:46 -0700160 @SkylarkCallable(name = "struct_field", documented = false, structField = true)
Ulf Adams89f012d2015-02-26 13:39:28 +0000161 public String structField() {
162 return "a";
163 }
laurentlb6659b4c2019-02-18 07:23:36 -0800164
165 @SkylarkCallable(
166 name = "struct_field_with_extra",
cparsons07460fc2018-06-20 10:41:48 -0700167 documented = false,
168 structField = true,
laurentlb28c30a72019-06-13 07:52:42 -0700169 useStarlarkSemantics = true)
laurentlb6659b4c2019-02-18 07:23:36 -0800170 public String structFieldWithExtra(StarlarkSemantics sem) {
cparsons07460fc2018-06-20 10:41:48 -0700171 return "struct_field_with_extra("
172 + (sem != null)
173 + ")";
174 }
cparsons7f475d72018-03-30 13:54:46 -0700175 @SkylarkCallable(name = "struct_field_callable", documented = false, structField = true)
Vladimir Moskvaa5b16742016-10-31 14:09:41 +0000176 public BuiltinFunction structFieldCallable() {
177 return foobar;
178 }
Benjamin Petersonbf1db782018-08-08 10:03:22 -0700179
180 @SkylarkCallable(name = "interrupted_struct_field", documented = false, structField = true)
181 public BuiltinFunction structFieldInterruptedCallable() throws InterruptedException {
182 throw new InterruptedException();
183 }
184
cparsons7f475d72018-03-30 13:54:46 -0700185 @SkylarkCallable(name = "function", documented = false, structField = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000186 public String function() {
187 return "a";
188 }
189 @SuppressWarnings("unused")
cparsonse661f882018-06-28 10:12:05 -0700190 @SkylarkCallable(name = "nullfunc_failing",
191 parameters = {
192 @Param(name = "p1", type = String.class),
193 @Param(name = "p2", type = Integer.class),
194 },
195 documented = false, allowReturnNones = false)
dslomov423dccc2017-04-11 12:18:09 +0000196 public SkylarkValue nullfuncFailing(String p1, Integer p2) {
Ulf Adams89f012d2015-02-26 13:39:28 +0000197 return null;
198 }
cparsons7f475d72018-03-30 13:54:46 -0700199 @SkylarkCallable(name = "nullfunc_working", documented = false, allowReturnNones = true)
dslomov423dccc2017-04-11 12:18:09 +0000200 public SkylarkValue nullfuncWorking() {
Ulf Adams89f012d2015-02-26 13:39:28 +0000201 return null;
202 }
cparsons7f475d72018-03-30 13:54:46 -0700203 @SkylarkCallable(name = "voidfunc", documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000204 public void voidfunc() {}
cparsons7f475d72018-03-30 13:54:46 -0700205 @SkylarkCallable(name = "string_list", documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000206 public ImmutableList<String> stringList() {
207 return ImmutableList.<String>of("a", "b");
208 }
cparsons7f475d72018-03-30 13:54:46 -0700209 @SkylarkCallable(name = "string", documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000210 public String string() {
211 return "a";
212 }
cparsons7f475d72018-03-30 13:54:46 -0700213 @SkylarkCallable(name = "string_list_dict", documented = false)
cparsonsaaab11f2018-01-31 11:00:11 -0800214 public Map<String, List<String>> stringListDict() {
215 return ImmutableMap.of("a", ImmutableList.of("b", "c"));
216 }
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000217
cparsons4baafac2018-04-11 11:09:17 -0700218 @SkylarkCallable(
219 name = "legacy_method",
220 documented = false,
221 parameters = {
222 @Param(name = "pos", positional = true, type = Boolean.class),
223 @Param(name = "legacyNamed", type = Boolean.class, positional = true, named = false,
224 legacyNamed = true),
225 @Param(name = "named", type = Boolean.class, positional = false, named = true),
226 })
227 public String legacyMethod(Boolean pos, Boolean legacyNamed, Boolean named) {
228 return "legacy_method("
229 + pos
230 + ", "
231 + legacyNamed
232 + ", "
233 + named
234 + ")";
235 }
cparsons979195e2018-04-09 15:43:22 -0700236
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000237 @SkylarkCallable(
238 name = "with_params",
cparsons7f475d72018-03-30 13:54:46 -0700239 documented = false,
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000240 parameters = {
cparsons23aab172018-07-13 11:47:17 -0700241 @Param(name = "pos1"),
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000242 @Param(name = "pos2", defaultValue = "False", type = Boolean.class),
243 @Param(
244 name = "posOrNamed",
245 defaultValue = "False",
246 type = Boolean.class,
247 positional = true,
248 named = true
249 ),
250 @Param(name = "named", type = Boolean.class, positional = false, named = true),
251 @Param(
252 name = "optionalNamed",
253 type = Boolean.class,
254 defaultValue = "False",
255 positional = false,
256 named = true
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +0000257 ),
258 @Param(
259 name = "nonNoneable",
260 type = Object.class,
261 defaultValue = "\"a\"",
262 positional = false,
263 named = true
264 ),
265 @Param(
266 name = "noneable",
Googlere5da53c2016-09-21 12:34:44 +0000267 type = Integer.class,
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +0000268 defaultValue = "None",
269 noneable = true,
270 positional = false,
271 named = true
272 ),
Dmitry Lomovd22e1de2017-09-25 08:53:50 -0400273 @Param(
274 name = "multi",
275 allowedTypes = {
276 @ParamType(type = String.class),
277 @ParamType(type = Integer.class),
278 @ParamType(type = SkylarkList.class, generic1 = Integer.class),
279 },
280 defaultValue = "None",
281 noneable = true,
282 positional = false,
283 named = true
284 )
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000285 }
286 )
287 public String withParams(
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +0000288 Integer pos1,
289 boolean pos2,
290 boolean posOrNamed,
291 boolean named,
292 boolean optionalNamed,
293 Object nonNoneable,
Dmitry Lomovd22e1de2017-09-25 08:53:50 -0400294 Object noneable,
295 Object multi) {
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000296 return "with_params("
297 + pos1
298 + ", "
299 + pos2
300 + ", "
301 + posOrNamed
302 + ", "
303 + named
304 + ", "
305 + optionalNamed
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +0000306 + ", "
cparsons5d446a72018-03-07 11:01:17 -0800307 + nonNoneable
Dmitry Lomovd22e1de2017-09-25 08:53:50 -0400308 + (noneable != Runtime.NONE ? ", " + noneable : "")
309 + (multi != Runtime.NONE ? ", " + multi : "")
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000310 + ")";
311 }
312
cparsons5d446a72018-03-07 11:01:17 -0800313 @SkylarkCallable(
cparsonsb380dc92018-12-05 13:57:39 -0800314 name = "with_extra",
315 documented = false,
316 useLocation = true,
317 useAst = true,
318 useEnvironment = true,
laurentlb28c30a72019-06-13 07:52:42 -0700319 useStarlarkSemantics = true,
cparsonsb380dc92018-12-05 13:57:39 -0800320 useContext = true)
cparsons5d446a72018-03-07 11:01:17 -0800321 public String withExtraInterpreterParams(
cparsonsb380dc92018-12-05 13:57:39 -0800322 Location location,
323 FuncallExpression func,
324 Environment env,
laurentlb6659b4c2019-02-18 07:23:36 -0800325 StarlarkSemantics sem,
cparsonsb380dc92018-12-05 13:57:39 -0800326 StarlarkContext context) {
cparsons5d446a72018-03-07 11:01:17 -0800327 return "with_extra("
328 + location.getStartLine()
329 + ", "
330 + func.getArguments().size()
331 + ", "
332 + env.isGlobal()
cparsons73e10162018-03-22 10:02:02 -0700333 + ", "
334 + (sem != null)
cparsonsb380dc92018-12-05 13:57:39 -0800335 + ", "
336 + (context != null)
cparsons5d446a72018-03-07 11:01:17 -0800337 + ")";
338 }
339
340 @SkylarkCallable(
laurentlb6659b4c2019-02-18 07:23:36 -0800341 name = "with_params_and_extra",
342 documented = false,
343 parameters = {
344 @Param(name = "pos1"),
345 @Param(name = "pos2", defaultValue = "False", type = Boolean.class),
346 @Param(
347 name = "posOrNamed",
348 defaultValue = "False",
349 type = Boolean.class,
350 positional = true,
351 named = true),
352 @Param(name = "named", type = Boolean.class, positional = false, named = true),
353 @Param(
354 name = "optionalNamed",
355 type = Boolean.class,
356 defaultValue = "False",
357 positional = false,
358 named = true),
359 @Param(
360 name = "nonNoneable",
361 type = Object.class,
362 defaultValue = "\"a\"",
363 positional = false,
364 named = true),
365 @Param(
366 name = "noneable",
367 type = Integer.class,
368 defaultValue = "None",
369 noneable = true,
370 positional = false,
371 named = true),
372 @Param(
373 name = "multi",
374 allowedTypes = {
375 @ParamType(type = String.class),
376 @ParamType(type = Integer.class),
377 @ParamType(type = SkylarkList.class, generic1 = Integer.class),
378 },
379 defaultValue = "None",
380 noneable = true,
381 positional = false,
382 named = true)
383 },
384 useAst = true,
385 useLocation = true,
386 useEnvironment = true,
laurentlb28c30a72019-06-13 07:52:42 -0700387 useStarlarkSemantics = true)
cparsons5d446a72018-03-07 11:01:17 -0800388 public String withParamsAndExtraInterpreterParams(
389 Integer pos1,
390 boolean pos2,
391 boolean posOrNamed,
392 boolean named,
393 boolean optionalNamed,
394 Object nonNoneable,
395 Object noneable,
396 Object multi,
397 Location location,
398 FuncallExpression func,
cparsons73e10162018-03-22 10:02:02 -0700399 Environment env,
laurentlb6659b4c2019-02-18 07:23:36 -0800400 StarlarkSemantics sem) {
cparsons5d446a72018-03-07 11:01:17 -0800401 return "with_params_and_extra("
402 + pos1
403 + ", "
404 + pos2
405 + ", "
406 + posOrNamed
407 + ", "
408 + named
409 + ", "
410 + optionalNamed
411 + ", "
412 + nonNoneable
413 + (noneable != Runtime.NONE ? ", " + noneable : "")
414 + (multi != Runtime.NONE ? ", " + multi : "")
415 + ", "
416 + location.getStartLine()
417 + ", "
418 + func.getArguments().size()
419 + ", "
420 + env.isGlobal()
cparsons73e10162018-03-22 10:02:02 -0700421 + ", "
422 + (sem != null)
cparsons5d446a72018-03-07 11:01:17 -0800423 + ")";
424 }
425
cparsons7520dcc2018-04-04 13:59:27 -0700426 @SkylarkCallable(name = "proxy_methods_object",
427 doc = "Returns a struct containing all callable method objects of this mock",
428 allowReturnNones = true)
429 public ClassObject proxyMethodsObject() {
430 ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
431 for (String nativeFunction : FuncallExpression.getMethodNames(Mock.class)) {
432 builder.put(nativeFunction,
433 FuncallExpression.getBuiltinCallable(this, nativeFunction));
434 }
cparsons0c5c1c62018-05-24 10:37:03 -0700435 return StructProvider.STRUCT.create(builder.build(), "no native callable '%s'");
cparsons7520dcc2018-04-04 13:59:27 -0700436 }
437
cparsons979195e2018-04-09 15:43:22 -0700438 @SkylarkCallable(
439 name = "with_args_and_env",
440 documented = false,
441 parameters = {
442 @Param(name = "pos1", type = Integer.class),
443 @Param(name = "pos2", defaultValue = "False", type = Boolean.class),
444 @Param(name = "named", type = Boolean.class, positional = false, named = true),
445 },
446 extraPositionals = @Param(name = "args"),
447 useEnvironment = true
448 )
449 public String withArgsAndEnv(
450 Integer pos1, boolean pos2, boolean named, SkylarkList<?> args, Environment env) {
451 String argsString =
452 "args(" + args.stream().map(Printer::debugPrint).collect(joining(", ")) + ")";
453 return "with_args_and_env("
454 + pos1
455 + ", "
456 + pos2
457 + ", "
458 + named
459 + ", "
460 + argsString
461 + ", "
462 + env.isGlobal()
463 + ")";
464 }
465
466 @SkylarkCallable(
467 name = "with_kwargs",
468 documented = false,
469 parameters = {
470 @Param(name = "pos", defaultValue = "False", type = Boolean.class),
471 @Param(name = "named", type = Boolean.class, positional = false, named = true),
472 },
473 extraKeywords = @Param(name = "kwargs")
474 )
475 public String withKwargs(boolean pos, boolean named, SkylarkDict<?, ?> kwargs)
476 throws EvalException {
477 String kwargsString =
478 "kwargs("
479 + kwargs
480 .getContents(String.class, Object.class, "kwargs")
481 .entrySet()
482 .stream()
483 .map(entry -> entry.getKey() + "=" + entry.getValue())
484 .collect(joining(", "))
485 + ")";
486 return "with_kwargs(" + pos + ", " + named + ", " + kwargsString + ")";
487 }
488
489 @SkylarkCallable(
490 name = "with_args_and_kwargs",
491 documented = false,
492 parameters = {
493 @Param(name = "foo", named = true, positional = true, type = String.class),
494 },
495 extraPositionals = @Param(name = "args"),
496 extraKeywords = @Param(name = "kwargs")
497 )
498 public String withArgsAndKwargs(String foo, SkylarkList<?> args, SkylarkDict<?, ?> kwargs)
499 throws EvalException {
500 String argsString =
501 "args(" + args.stream().map(Printer::debugPrint).collect(joining(", ")) + ")";
502 String kwargsString =
503 "kwargs("
504 + kwargs
505 .getContents(String.class, Object.class, "kwargs")
506 .entrySet()
507 .stream()
508 .map(entry -> entry.getKey() + "=" + entry.getValue())
509 .collect(joining(", "))
510 + ")";
511 return "with_args_and_kwargs(" + foo + ", " + argsString + ", " + kwargsString + ")";
512 }
513
Benjamin Petersonaf53a112019-06-05 10:47:11 -0700514 @SkylarkCallable(name = "raise_unchecked_exception", documented = false)
515 public void raiseUncheckedException() {
516 throw new InternalError("buggy code");
517 }
518
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000519 @Override
520 public String toString() {
521 return "<mock>";
522 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000523 }
524
525 @SkylarkModule(name = "MockInterface", doc = "")
526 static interface MockInterface {
cparsonse661f882018-06-28 10:12:05 -0700527 @SkylarkCallable(name = "is_empty_interface",
528 parameters = { @Param(name = "str", type = String.class) },
529 documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000530 public Boolean isEmptyInterface(String str);
531 }
532
cparsons4dc97ff2018-05-24 13:48:22 -0700533 @SkylarkModule(name = "MockSubClass", doc = "")
Ulf Adams89f012d2015-02-26 13:39:28 +0000534 static final class MockSubClass extends Mock implements MockInterface {
535 @Override
536 public Boolean isEmpty(String str) {
537 return str.isEmpty();
538 }
539 @Override
540 public Boolean isEmptyInterface(String str) {
541 return str.isEmpty();
542 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000543 }
544
cparsons7f475d72018-03-30 13:54:46 -0700545 @SkylarkModule(name = "MockClassObject", documented = false, doc = "")
Ulf Adams89f012d2015-02-26 13:39:28 +0000546 static final class MockClassObject implements ClassObject {
547 @Override
548 public Object getValue(String name) {
549 switch (name) {
550 case "field": return "a";
551 case "nset": return NestedSetBuilder.stableOrder().build();
vladmos3ad44e32017-05-04 18:30:51 +0200552 default: return null;
Ulf Adams89f012d2015-02-26 13:39:28 +0000553 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000554 }
555
556 @Override
brandjond331fa72017-12-28 07:38:31 -0800557 public ImmutableCollection<String> getFieldNames() {
Ulf Adams89f012d2015-02-26 13:39:28 +0000558 return ImmutableList.of("field", "nset");
559 }
560
561 @Override
brandjond331fa72017-12-28 07:38:31 -0800562 public String getErrorMessageForUnknownField(String name) {
Ulf Adams89f012d2015-02-26 13:39:28 +0000563 return null;
564 }
565 }
566
cparsonsd3d05b22018-05-24 12:12:07 -0700567 @SkylarkModule(name = "ParamterizedMock", doc = "")
568 static interface ParameterizedApi<ObjectT> {
569 @SkylarkCallable(
570 name = "method",
571 documented = false,
572 parameters = {
573 @Param(name = "foo", named = true, positional = true, type = Object.class),
574 }
575 )
576 public ObjectT method(ObjectT o);
577 }
578
579 static final class ParameterizedMock implements ParameterizedApi<String> {
580 @Override
581 public String method(String o) {
582 return o;
583 }
584 }
585
586 // Verifies that a method implementation overriding a parameterized annotated interface method
587 // is still treated as skylark-callable. Concretely, method() below should be treated as
588 // callable even though its method signature isn't an *exact* match of the annotated method
589 // declaration, due to the interface's method declaration being generic.
590 @Test
591 public void testParameterizedMock() throws Exception {
592 new SkylarkTest()
593 .update("mock", new ParameterizedMock())
594 .setUp("result = mock.method('bar')")
595 .testLookup("result", "bar");
Ulf Adams89f012d2015-02-26 13:39:28 +0000596 }
597
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000598 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000599 public void testSimpleIf() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000600 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000601 " a = 0",
602 " x = 0",
603 " if x: a = 5",
604 " return a",
Florian Weikert28da3652015-07-01 14:52:30 +0000605 "a = foo()").testLookup("a", 0);
Ulf Adams89f012d2015-02-26 13:39:28 +0000606 }
607
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000608 @Test
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000609 public void testIfPass() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000610 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000611 " a = 1",
612 " x = True",
613 " if x: pass",
614 " return a",
Florian Weikert28da3652015-07-01 14:52:30 +0000615 "a = foo()").testLookup("a", 1);
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000616 }
617
618 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000619 public void testNestedIf() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000620 executeNestedIf(0, 0, 0);
621 executeNestedIf(1, 0, 3);
622 executeNestedIf(1, 1, 5);
Ulf Adams89f012d2015-02-26 13:39:28 +0000623 }
624
Florian Weikert28da3652015-07-01 14:52:30 +0000625 private void executeNestedIf(int x, int y, int expected) throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000626 String fun = String.format("foo%s%s", x, y);
Florian Weikert28da3652015-07-01 14:52:30 +0000627 new SkylarkTest().setUp("def " + fun + "():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000628 " x = " + x,
629 " y = " + y,
630 " a = 0",
631 " b = 0",
632 " if x:",
633 " if y:",
634 " a = 2",
635 " b = 3",
636 " return a + b",
Florian Weikert28da3652015-07-01 14:52:30 +0000637 "x = " + fun + "()").testLookup("x", expected);
Ulf Adams89f012d2015-02-26 13:39:28 +0000638 }
639
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000640 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000641 public void testIfElse() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000642 executeIfElse("foo", "something", 2);
643 executeIfElse("bar", "", 3);
Ulf Adams89f012d2015-02-26 13:39:28 +0000644 }
645
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000646 private void executeIfElse(String fun, String y, int expected) throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000647 new SkylarkTest().setUp("def " + fun + "():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000648 " y = '" + y + "'",
649 " x = 5",
650 " if x:",
651 " if y: a = 2",
652 " else: a = 3",
Florian Weikert28da3652015-07-01 14:52:30 +0000653 " return a",
654 "z = " + fun + "()").testLookup("z", expected);
Ulf Adams89f012d2015-02-26 13:39:28 +0000655 }
656
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000657 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000658 public void testIfElifElse_IfExecutes() throws Exception {
659 execIfElifElse(1, 0, 1);
660 }
661
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000662 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000663 public void testIfElifElse_ElifExecutes() throws Exception {
664 execIfElifElse(0, 1, 2);
665 }
666
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000667 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000668 public void testIfElifElse_ElseExecutes() throws Exception {
669 execIfElifElse(0, 0, 3);
670 }
671
672 private void execIfElifElse(int x, int y, int v) throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000673 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000674 " x = " + x + "",
675 " y = " + y + "",
676 " if x:",
677 " return 1",
678 " elif y:",
679 " return 2",
680 " else:",
681 " return 3",
Florian Weikert28da3652015-07-01 14:52:30 +0000682 "v = foo()").testLookup("v", v);
Ulf Adams89f012d2015-02-26 13:39:28 +0000683 }
684
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000685 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000686 public void testForOnList() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000687 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000688 " s = ''",
689 " for i in ['hello', ' ', 'world']:",
690 " s = s + i",
691 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000692 "s = foo()").testLookup("s", "hello world");
Ulf Adams89f012d2015-02-26 13:39:28 +0000693 }
694
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000695 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000696 public void testForAssignmentList() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000697 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000698 " d = ['a', 'b', 'c']",
699 " s = ''",
700 " for i in d:",
701 " s = s + i",
Florian Weikert28da3652015-07-01 14:52:30 +0000702 " d = ['d', 'e', 'f']", // check that we use the old list
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000703 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000704 "s = foo()").testLookup("s", "abc");
Ulf Adams89f012d2015-02-26 13:39:28 +0000705 }
706
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000707 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000708 public void testForAssignmentDict() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000709 new SkylarkTest().setUp("def func():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000710 " d = {'a' : 1, 'b' : 2, 'c' : 3}",
711 " s = ''",
712 " for i in d:",
713 " s = s + i",
714 " d = {'d' : 1, 'e' : 2, 'f' : 3}",
715 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000716 "s = func()").testLookup("s", "abc");
Ulf Adams89f012d2015-02-26 13:39:28 +0000717 }
718
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000719 @Test
Jon Brandvein15775b22016-07-25 15:13:44 +0000720 public void testForUpdateList() throws Exception {
Jon Brandvein15775b22016-07-25 15:13:44 +0000721 new SkylarkTest().setUp("def foo():",
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000722 " xs = [1, 2, 3]",
Jon Brandvein15775b22016-07-25 15:13:44 +0000723 " for x in xs:",
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000724 " if x == 1:",
725 " xs.append(10)"
726 ).testIfErrorContains("trying to mutate a locked object", "foo()");
Jon Brandvein15775b22016-07-25 15:13:44 +0000727 }
728
729 @Test
730 public void testForUpdateDict() throws Exception {
Jon Brandvein15775b22016-07-25 15:13:44 +0000731 new SkylarkTest().setUp("def foo():",
732 " d = {'a': 1, 'b': 2, 'c': 3}",
Jon Brandvein15775b22016-07-25 15:13:44 +0000733 " for k in d:",
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000734 " d[k] *= 2"
735 ).testIfErrorContains("trying to mutate a locked object", "foo()");
736 }
737
738 @Test
739 public void testForUnlockedAfterBreak() throws Exception {
740 new SkylarkTest().setUp("def foo():",
741 " xs = [1, 2]",
742 " for x in xs:",
743 " break",
744 " xs.append(3)",
745 " return xs"
746 ).testEval("foo()", "[1, 2, 3]");
747 }
748
749 @Test
750 public void testForNestedOnSameListStillLocked() throws Exception {
751 new SkylarkTest().setUp("def foo():",
752 " xs = [1, 2]",
753 " ys = []",
754 " for x1 in xs:",
755 " for x2 in xs:",
756 " ys.append(x1 * x2)",
757 " xs.append(4)",
758 " return ys"
759 ).testIfErrorContains("trying to mutate a locked object", "foo()");
760 }
761
762 @Test
763 public void testForNestedOnSameListErrorMessage() throws Exception {
764 new SkylarkTest().setUp("def foo():",
765 " xs = [1, 2]",
766 " ys = []",
767 " for x1 in xs:",
768 " for x2 in xs:",
769 " ys.append(x1 * x2)",
770 " xs.append(4)",
771 " return ys"
772 // No file name in message, due to how test is set up.
Carmi Grushko46bf88c2017-02-20 22:37:15 +0000773 ).testIfErrorContains("Object locked at the following location(s): :4:3, :5:5", "foo()");
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000774 }
775
776 @Test
777 public void testForNestedOnSameListUnlockedAtEnd() throws Exception {
778 new SkylarkTest().setUp("def foo():",
779 " xs = [1, 2]",
780 " ys = []",
781 " for x1 in xs:",
782 " for x2 in xs:",
783 " ys.append(x1 * x2)",
784 " xs.append(4)",
785 " return ys"
786 ).testEval("foo()", "[1, 2, 2, 4]");
787 }
788
789 @Test
790 public void testForNestedWithListCompGood() throws Exception {
791 new SkylarkTest().setUp("def foo():",
792 " xs = [1, 2]",
793 " ys = []",
794 " for x in xs:",
795 " zs = [None for x in xs for y in (ys.append(x) or ys)]",
796 " return ys"
797 ).testEval("foo()", "[1, 2, 1, 2]");
798 }
799 @Test
800 public void testForNestedWithListCompBad() throws Exception {
801 new SkylarkTest().setUp("def foo():",
802 " xs = [1, 2, 3]",
803 " ys = []",
804 " for x in xs:",
805 " zs = [None for x in xs for y in (xs.append(x) or ys)]",
806 " return ys"
807 ).testIfErrorContains("trying to mutate a locked object", "foo()");
Jon Brandvein15775b22016-07-25 15:13:44 +0000808 }
809
810 @Test
811 public void testForDeepUpdate() throws Exception {
812 // Check that indirectly reachable values can still be manipulated as normal.
813 new SkylarkTest().setUp("def foo():",
814 " xs = [['a'], ['b'], ['c']]",
815 " ys = []",
816 " for x in xs:",
817 " for y in x:",
818 " ys.append(y)",
819 " xs[2].append(x[0])",
820 " return ys",
821 "ys = foo()").testLookup("ys", MutableList.of(null, "a", "b", "c", "a", "b"));
822 }
823
824 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000825 public void testForNotIterable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000826 new SkylarkTest()
827 .update("mock", new Mock())
Florian Weikertc1d54ec2015-08-26 14:06:58 +0000828 .testIfErrorContains(
829 "type 'int' is not iterable",
830 "def func():",
831 " for i in mock.value_of('1'): a = i",
832 "func()\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000833 }
834
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000835 @Test
laurentlb26f843d2019-02-20 06:44:05 -0800836 public void testForStringNotIterable() throws Exception {
837 new SkylarkTest()
838 .update("mock", new Mock())
839 .testIfErrorContains(
840 "type 'string' is not iterable", "def func():", " for i in 'abc': a = i", "func()\n");
841 }
842
843 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000844 public void testForOnDictionary() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000845 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000846 " d = {1: 'a', 2: 'b', 3: 'c'}",
847 " s = ''",
848 " for i in d: s = s + d[i]",
849 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000850 "s = foo()").testLookup("s", "abc");
Ulf Adams89f012d2015-02-26 13:39:28 +0000851 }
852
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000853 @Test
Francois-Rene Rideau6c10eac2015-09-17 19:17:20 +0000854 public void testBadDictKey() throws Exception {
855 new SkylarkTest().testIfErrorContains(
856 "unhashable type: 'list'",
857 "{ [1, 2]: [3, 4] }");
858 }
859
860 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000861 public void testForLoopReuseVariable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000862 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000863 " s = ''",
864 " for i in ['a', 'b']:",
865 " for i in ['c', 'd']: s = s + i",
866 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000867 "s = foo()").testLookup("s", "cdcd");
Ulf Adams89f012d2015-02-26 13:39:28 +0000868 }
869
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000870 @Test
Laurent Le Brun741824b2015-03-20 15:10:19 +0000871 public void testForLoopMultipleVariables() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000872 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000873 " s = ''",
874 " for [i, j] in [[1, 2], [3, 4]]:",
875 " s = s + str(i) + str(j) + '.'",
876 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000877 "s = foo()").testLookup("s", "12.34.");
Laurent Le Brun741824b2015-03-20 15:10:19 +0000878 }
879
880 @Test
Florian Weikert917ceaa2015-06-10 13:54:26 +0000881 public void testForLoopBreak() throws Exception {
882 simpleFlowTest("break", 1);
883 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000884
Florian Weikert917ceaa2015-06-10 13:54:26 +0000885 @Test
886 public void testForLoopContinue() throws Exception {
887 simpleFlowTest("continue", 10);
888 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000889
Florian Weikert917ceaa2015-06-10 13:54:26 +0000890 @SuppressWarnings("unchecked")
891 private void simpleFlowTest(String statement, int expected) throws Exception {
892 eval("def foo():",
893 " s = 0",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000894 " hit = 0",
895 " for i in range(0, 10):",
896 " s = s + 1",
897 " " + statement + "",
898 " hit = 1",
899 " return [s, hit]",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000900 "x = foo()");
901 assertThat((Iterable<Object>) lookup("x")).containsExactly(expected, 0).inOrder();
902 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000903
904 @Test
Florian Weikert917ceaa2015-06-10 13:54:26 +0000905 public void testForLoopBreakFromDeeperBlock() throws Exception {
906 flowFromDeeperBlock("break", 1);
907 flowFromNestedBlocks("break", 29);
908 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000909
910 @Test
Florian Weikert917ceaa2015-06-10 13:54:26 +0000911 public void testForLoopContinueFromDeeperBlock() throws Exception {
912 flowFromDeeperBlock("continue", 5);
913 flowFromNestedBlocks("continue", 39);
914 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000915
Florian Weikert917ceaa2015-06-10 13:54:26 +0000916 private void flowFromDeeperBlock(String statement, int expected) throws Exception {
917 eval("def foo():",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000918 " s = 0",
919 " for i in range(0, 10):",
920 " if i % 2 != 0:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000921 " " + statement + "",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000922 " s = s + 1",
923 " return s",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000924 "x = foo()");
925 assertThat(lookup("x")).isEqualTo(expected);
926 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000927
Florian Weikert917ceaa2015-06-10 13:54:26 +0000928 private void flowFromNestedBlocks(String statement, int expected) throws Exception {
929 eval("def foo2():",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000930 " s = 0",
931 " for i in range(1, 41):",
932 " if i % 2 == 0:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000933 " if i % 3 == 0:",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000934 " if i % 5 == 0:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000935 " " + statement + "",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000936 " s = s + 1",
937 " return s",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000938 "y = foo2()");
939 assertThat(lookup("y")).isEqualTo(expected);
940 }
941
942 @Test
943 public void testNestedForLoopsMultipleBreaks() throws Exception {
944 nestedLoopsTest("break", 2, 6, 6);
945 }
946
947 @Test
948 public void testNestedForLoopsMultipleContinues() throws Exception {
949 nestedLoopsTest("continue", 4, 20, 20);
950 }
951
952 @SuppressWarnings("unchecked")
953 private void nestedLoopsTest(String statement, Integer outerExpected, int firstExpected,
954 int secondExpected) throws Exception {
955 eval("def foo():",
956 " outer = 0",
957 " first = 0",
958 " second = 0",
959 " for i in range(0, 5):",
960 " for j in range(0, 5):",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000961 " if j == 2:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000962 " " + statement + "",
963 " first = first + 1",
964 " for k in range(0, 5):",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000965 " if k == 2:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000966 " " + statement + "",
967 " second = second + 1",
968 " if i == 2:",
969 " " + statement + "",
970 " outer = outer + 1",
971 " return [outer, first, second]",
972 "x = foo()");
973 assertThat((Iterable<Object>) lookup("x"))
974 .containsExactly(outerExpected, firstExpected, secondExpected).inOrder();
975 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000976
Florian Weikert917ceaa2015-06-10 13:54:26 +0000977 @Test
978 public void testForLoopBreakError() throws Exception {
979 flowStatementInsideFunction("break");
980 flowStatementAfterLoop("break");
981 }
982
983 @Test
984 public void testForLoopContinueError() throws Exception {
985 flowStatementInsideFunction("continue");
986 flowStatementAfterLoop("continue");
987 }
988
989 private void flowStatementInsideFunction(String statement) throws Exception {
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000990 checkEvalErrorContains(statement + " statement must be inside a for loop",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000991 "def foo():",
brandjone5d95fb2017-07-13 17:23:09 +0200992 " " + statement,
Florian Weikert917ceaa2015-06-10 13:54:26 +0000993 "x = foo()");
994 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000995
Florian Weikert917ceaa2015-06-10 13:54:26 +0000996 private void flowStatementAfterLoop(String statement) throws Exception {
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000997 checkEvalErrorContains(statement + " statement must be inside a for loop",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000998 "def foo2():",
999 " for i in range(0, 3):",
1000 " pass",
brandjone5d95fb2017-07-13 17:23:09 +02001001 " " + statement,
Florian Weikert917ceaa2015-06-10 13:54:26 +00001002 "y = foo2()");
1003 }
Florian Weikert28da3652015-07-01 14:52:30 +00001004
Florian Weikert917ceaa2015-06-10 13:54:26 +00001005 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001006 public void testNoneAssignment() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001007 new SkylarkTest()
1008 .setUp("def foo(x=None):", " x = 1", " x = None", " return 2", "s = foo()")
1009 .testLookup("s", 2);
Ulf Adams89f012d2015-02-26 13:39:28 +00001010 }
1011
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001012 @Test
Laurent Le Brun88014fe2015-06-17 16:02:16 +00001013 public void testReassignment() throws Exception {
1014 eval("def foo(x=None):",
1015 " x = 1",
1016 " x = [1, 2]",
1017 " x = 'str'",
1018 " return x",
1019 "s = foo()");
1020 assertThat(lookup("s")).isEqualTo("str");
1021 }
1022
1023 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001024 public void testJavaCalls() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001025 new SkylarkTest()
1026 .update("mock", new Mock())
1027 .setUp("b = mock.is_empty('a')")
1028 .testLookup("b", Boolean.FALSE);
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 testJavaCallsOnSubClass() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001033 new SkylarkTest()
1034 .update("mock", new MockSubClass())
1035 .setUp("b = mock.is_empty('a')")
1036 .testLookup("b", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001037 }
1038
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001039 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001040 public void testJavaCallsOnInterface() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001041 new SkylarkTest()
1042 .update("mock", new MockSubClass())
1043 .setUp("b = mock.is_empty_interface('a')")
1044 .testLookup("b", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001045 }
1046
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001047 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001048 public void testJavaCallsNotSkylarkCallable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001049 new SkylarkTest()
1050 .update("mock", new Mock())
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001051 .testIfExactError("type 'Mock' has no method value()", "mock.value()");
Laurent Le Brun648f8f32015-09-09 19:46:29 +00001052 }
1053
1054 @Test
1055 public void testNoOperatorIndex() throws Exception {
1056 new SkylarkTest()
1057 .update("mock", new Mock())
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001058 .testIfExactError("type 'Mock' has no operator [](int)", "mock[2]");
Ulf Adams89f012d2015-02-26 13:39:28 +00001059 }
1060
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001061 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001062 public void testJavaCallsNoMethod() throws Exception {
Francois-Rene Rideau676905a2015-08-31 15:39:09 +00001063 new SkylarkTest()
1064 .update("mock", new Mock())
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001065 .testIfExactError("type 'Mock' has no method bad()", "mock.bad()");
Ulf Adams89f012d2015-02-26 13:39:28 +00001066 }
1067
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001068 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001069 public void testJavaCallsNoMethodErrorMsg() throws Exception {
Laurent Le Brun648f8f32015-09-09 19:46:29 +00001070 new SkylarkTest()
cparsons03035142019-01-15 13:35:22 -08001071 .testIfExactError("type 'int' has no method bad()", "s = 3.bad('a', 'b', 'c')");
Ulf Adams89f012d2015-02-26 13:39:28 +00001072 }
1073
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001074 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001075 public void testJavaCallWithKwargs() throws Exception {
Francois-Rene Rideau676905a2015-08-31 15:39:09 +00001076 new SkylarkTest()
1077 .update("mock", new Mock())
cparsons03035142019-01-15 13:35:22 -08001078 .testIfExactError("type 'Mock' has no method isEmpty()", "mock.isEmpty(str='abc')");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001079 }
1080
cparsonsaaab11f2018-01-31 11:00:11 -08001081 @Test
1082 public void testStringListDictValues() throws Exception {
1083 new SkylarkTest()
1084 .update("mock", new Mock())
1085 .setUp(
1086 "def func(mock):",
1087 " for i, v in mock.string_list_dict().items():",
1088 " modified_list = v + ['extra_string']",
1089 " return modified_list",
1090 "m = func(mock)")
1091 .testLookup("m", MutableList.of(env, "b", "c", "extra_string"));
1092 }
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001093
1094 @Test
cparsons7520dcc2018-04-04 13:59:27 -07001095 public void testProxyMethodsObject() throws Exception {
1096 new SkylarkTest()
1097 .update("mock", new Mock())
1098 .setUp(
1099 "m = mock.proxy_methods_object()",
1100 "b = m.with_params(1, True, named=True)")
1101 .testLookup("b", "with_params(1, true, false, true, false, a)");
1102 }
1103
cparsons4baafac2018-04-11 11:09:17 -07001104 @Test
1105 public void testLegacyNamed() throws Exception {
1106 new SkylarkTest()
1107 .update("mock", new Mock())
1108 .setUp(
1109 "b = mock.legacy_method(True, legacyNamed=True, named=True)")
1110 .testLookup("b", "legacy_method(true, true, true)");
1111
1112 new SkylarkTest()
1113 .update("mock", new Mock())
1114 .setUp(
1115 "b = mock.legacy_method(True, True, named=True)")
1116 .testLookup("b", "legacy_method(true, true, true)");
1117
1118 // Verify legacyNamed also works with proxy method objects.
1119 new SkylarkTest()
1120 .update("mock", new Mock())
1121 .setUp(
1122 "m = mock.proxy_methods_object()",
1123 "b = m.legacy_method(True, legacyNamed=True, named=True)")
1124 .testLookup("b", "legacy_method(true, true, true)");
1125
1126 new SkylarkTest()
1127 .update("mock", new Mock())
1128 .setUp(
1129 "m = mock.proxy_methods_object()",
1130 "b = m.legacy_method(True, True, named=True)")
1131 .testLookup("b", "legacy_method(true, true, true)");
1132 }
1133
cparsons74f78972018-04-06 12:55:47 -07001134 /**
1135 * This test verifies an error is raised when a method parameter is set both positionally and
1136 * by name.
1137 */
1138 @Test
1139 public void testArgSpecifiedBothByNameAndPosition() throws Exception {
1140 // in with_params, 'posOrNamed' is positional parameter index 2. So by specifying both
1141 // posOrNamed by name and three positional parameters, there is a conflict.
1142 new SkylarkTest()
1143 .update("mock", new Mock())
1144 .testIfErrorContains("got multiple values for keyword argument 'posOrNamed'",
1145 "mock.with_params(1, True, True, posOrNamed=True, named=True)");
1146 }
1147
1148 @Test
1149 public void testTooManyPositionalArgs() throws Exception {
1150 new SkylarkTest()
1151 .update("mock", new Mock())
1152 .testIfErrorContains("expected no more than 3 positional arguments, but got 4",
1153 "mock.with_params(1, True, True, 'toomany', named=True)");
1154
1155 new SkylarkTest()
1156 .update("mock", new Mock())
1157 .testIfErrorContains("expected no more than 3 positional arguments, but got 5",
1158 "mock.with_params(1, True, True, 'toomany', 'alsotoomany', named=True)");
1159
1160 new SkylarkTest()
1161 .update("mock", new Mock())
1162 .testIfErrorContains("expected no more than 1 positional arguments, but got 2",
1163 "mock.is_empty('a', 'b')");
1164 }
1165
cparsons7520dcc2018-04-04 13:59:27 -07001166 @Test
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001167 public void testJavaCallWithPositionalAndKwargs() throws Exception {
1168 new SkylarkTest()
1169 .update("mock", new Mock())
1170 .setUp("b = mock.with_params(1, True, named=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001171 .testLookup("b", "with_params(1, true, false, true, false, a)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001172 new SkylarkTest()
1173 .update("mock", new Mock())
Dmitry Lomovd22e1de2017-09-25 08:53:50 -04001174 .setUp("b = mock.with_params(1, True, named=True, multi=1)")
1175 .testLookup("b", "with_params(1, true, false, true, false, a, 1)");
1176 new SkylarkTest()
1177 .update("mock", new Mock())
1178 .setUp("b = mock.with_params(1, True, named=True, multi='abc')")
1179 .testLookup("b", "with_params(1, true, false, true, false, a, abc)");
1180
1181 new SkylarkTest()
1182 .update("mock", new Mock())
1183 .setUp("b = mock.with_params(1, True, named=True, multi=[1,2,3])")
1184 .testLookup("b", "with_params(1, true, false, true, false, a, [1, 2, 3])");
1185
1186 new SkylarkTest()
1187 .update("mock", new Mock())
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001188 .setUp("")
1189 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001190 "parameter 'named' has no default value, for call to "
1191 + "method with_params(pos1, pos2 = False, posOrNamed = False, named, "
1192 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1193 + "of 'Mock'",
Pedro Liberal Fernandez92f06a52016-09-28 07:33:42 +00001194 "mock.with_params(1, True)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001195 new SkylarkTest()
1196 .update("mock", new Mock())
1197 .setUp("")
1198 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001199 "parameter 'named' has no default value, for call to "
1200 + "method with_params(pos1, pos2 = False, posOrNamed = False, named, "
1201 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001202 + "of 'Mock'",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001203 "mock.with_params(1, True, True)");
1204 new SkylarkTest()
1205 .update("mock", new Mock())
1206 .setUp("b = mock.with_params(1, True, True, named=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001207 .testLookup("b", "with_params(1, true, true, true, false, a)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001208 new SkylarkTest()
1209 .update("mock", new Mock())
1210 .setUp("b = mock.with_params(1, True, named=True, posOrNamed=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001211 .testLookup("b", "with_params(1, true, true, true, false, a)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001212 new SkylarkTest()
1213 .update("mock", new Mock())
1214 .setUp("b = mock.with_params(1, True, named=True, posOrNamed=True, optionalNamed=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001215 .testLookup("b", "with_params(1, true, true, true, true, a)");
Pedro Liberal Fernandez837dbc12016-08-18 14:13:01 +00001216 new SkylarkTest()
1217 .update("mock", new Mock())
1218 .setUp("")
1219 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001220 "unexpected keyword 'n', for call to "
1221 + "method with_params(pos1, pos2 = False, posOrNamed = False, named, "
1222 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1223 + "of 'Mock'",
Pedro Liberal Fernandez837dbc12016-08-18 14:13:01 +00001224 "mock.with_params(1, True, named=True, posOrNamed=True, n=2)");
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001225 new SkylarkTest()
1226 .update("mock", new Mock())
1227 .setUp("")
1228 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001229 "parameter 'nonNoneable' cannot be None, for call to method "
1230 + "with_params(pos1, pos2 = False, posOrNamed = False, named, "
1231 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1232 + "of 'Mock'",
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001233 "mock.with_params(1, True, True, named=True, optionalNamed=False, nonNoneable=None)");
Dmitry Lomovd22e1de2017-09-25 08:53:50 -04001234
1235 new SkylarkTest()
1236 .update("mock", new Mock())
1237 .setUp("")
1238 .testIfExactError(
cparsonsa95884e2018-03-21 11:06:13 -07001239 "expected value of type 'string or int or sequence of ints or NoneType' for parameter"
cparsons03035142019-01-15 13:35:22 -08001240 + " 'multi', for call to method "
1241 + "with_params(pos1, pos2 = False, posOrNamed = False, named, "
1242 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1243 + "of 'Mock'",
Dmitry Lomovd22e1de2017-09-25 08:53:50 -04001244 "mock.with_params(1, True, named=True, multi=False)");
1245
1246 // We do not enforce list item parameter type constraints.
1247 // Test for this behavior.
1248 new SkylarkTest()
1249 .update("mock", new Mock())
1250 .setUp("b = mock.with_params(1, True, named=True, multi=['a', 'b'])")
1251 .testLookup("b", "with_params(1, true, false, true, false, a, [\"a\", \"b\"])");
Ulf Adams89f012d2015-02-26 13:39:28 +00001252 }
1253
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001254 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001255 public void testNoJavaCallsWithoutSkylark() throws Exception {
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001256 new SkylarkTest().testIfExactError("type 'int' has no method to_string()", "s = 3.to_string()");
Laurent Le Brun648f8f32015-09-09 19:46:29 +00001257 }
Ulf Adams89f012d2015-02-26 13:39:28 +00001258
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001259 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001260 public void testStructAccess() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001261 new SkylarkTest()
1262 .update("mock", new Mock())
1263 .setUp("v = mock.struct_field")
1264 .testLookup("v", "a");
Ulf Adams89f012d2015-02-26 13:39:28 +00001265 }
1266
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001267 @Test
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001268 public void testStructAccessAsFuncallNonCallable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001269 new SkylarkTest()
1270 .update("mock", new Mock())
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001271 .testIfExactError("'string' object is not callable", "v = mock.struct_field()");
1272 }
1273
1274 @Test
cparsons0e866862018-04-24 08:07:02 -07001275 public void testSelfCall() throws Exception {
1276 new SkylarkTest()
1277 .update("mock", new Mock())
1278 .setUp("v = mock('bestmock')")
1279 .testLookup("v", "I'm a mock named bestmock");
1280
1281 new SkylarkTest()
1282 .update("mock", new Mock())
1283 .setUp("mockfunction = mock", "v = mockfunction('bestmock')")
1284 .testLookup("v", "I'm a mock named bestmock");
1285
1286 new SkylarkTest()
1287 .update("mock", new Mock())
1288 .testIfErrorContains(
cparsons03035142019-01-15 13:35:22 -08001289 "expected value of type 'string' for parameter 'pos', for call to function MockFn(pos)",
cparsons0e866862018-04-24 08:07:02 -07001290 "v = mock(1)");
1291 }
1292
1293 @Test
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001294 public void testStructAccessAsFuncall() throws Exception {
1295 foobar.configure(getClass().getDeclaredField("foobar").getAnnotation(SkylarkSignature.class));
1296 new SkylarkTest()
1297 .update("mock", new Mock())
1298 .setUp("v = mock.struct_field_callable()")
1299 .testLookup("v", "foobar");
Ulf Adams89f012d2015-02-26 13:39:28 +00001300 }
1301
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001302 @Test
Benjamin Petersonbf1db782018-08-08 10:03:22 -07001303 public void testCallingInterruptedStructField() throws Exception {
1304 update("mock", new Mock());
1305 assertThrows(InterruptedException.class, () -> eval("mock.interrupted_struct_field()"));
1306 }
1307
1308 @Test
1309 public void testCallingInterruptedFunction() throws Exception {
1310 interruptedFunction.configure(
1311 getClass().getDeclaredField("interruptedFunction").getAnnotation(SkylarkSignature.class));
1312 update("interrupted_function", interruptedFunction);
1313 assertThrows(InterruptedException.class, () -> eval("interrupted_function()"));
1314 }
1315
1316 @Test
Benjamin Petersonaf53a112019-06-05 10:47:11 -07001317 public void testCallingMethodThatRaisesUncheckedException() throws Exception {
1318 update("mock", new Mock());
1319 assertThrows(InternalError.class, () -> eval("mock.raise_unchecked_exception()"));
1320 }
1321
1322 @Test
cparsons5d446a72018-03-07 11:01:17 -08001323 public void testJavaFunctionWithExtraInterpreterParams() throws Exception {
1324 new SkylarkTest()
1325 .update("mock", new Mock())
1326 .setUp("v = mock.with_extra()")
cparsonsb380dc92018-12-05 13:57:39 -08001327 .testLookup("v", "with_extra(1, 0, true, true, true)");
cparsons5d446a72018-03-07 11:01:17 -08001328 }
1329
1330 @Test
cparsons07460fc2018-06-20 10:41:48 -07001331 public void testStructFieldWithExtraInterpreterParams() throws Exception {
1332 new SkylarkTest()
1333 .update("mock", new Mock())
1334 .setUp("v = mock.struct_field_with_extra")
1335 .testLookup("v", "struct_field_with_extra(true)");
1336 }
1337
1338 @Test
cparsons5d446a72018-03-07 11:01:17 -08001339 public void testJavaFunctionWithParamsAndExtraInterpreterParams() throws Exception {
1340 new SkylarkTest()
1341 .update("mock", new Mock())
1342 .setUp("b = mock.with_params_and_extra(1, True, named=True)")
cparsons73e10162018-03-22 10:02:02 -07001343 .testLookup("b", "with_params_and_extra(1, true, false, true, false, a, 1, 3, true, true)");
cparsons5d446a72018-03-07 11:01:17 -08001344 }
1345
1346 @Test
cparsons979195e2018-04-09 15:43:22 -07001347 public void testJavaFunctionWithExtraArgsAndEnv() throws Exception {
1348 new SkylarkTest()
1349 .update("mock", new Mock())
1350 .setUp("b = mock.with_args_and_env(1, True, 'extraArg1', 'extraArg2', named=True)")
1351 .testLookup("b", "with_args_and_env(1, true, true, args(extraArg1, extraArg2), true)");
1352
1353 // Use an args list.
1354 new SkylarkTest()
1355 .update("mock", new Mock())
1356 .setUp(
1357 "myargs = ['extraArg2']",
1358 "b = mock.with_args_and_env(1, True, 'extraArg1', named=True, *myargs)")
1359 .testLookup("b", "with_args_and_env(1, true, true, args(extraArg1, extraArg2), true)");
1360 }
1361
1362 @Test
1363 public void testJavaFunctionWithExtraKwargs() throws Exception {
1364 new SkylarkTest()
1365 .update("mock", new Mock())
1366 .setUp("b = mock.with_kwargs(True, extraKey1=True, named=True, extraKey2='x')")
1367 .testLookup("b", "with_kwargs(true, true, kwargs(extraKey1=true, extraKey2=x))");
1368
1369 // Use a kwargs dict.
1370 new SkylarkTest()
1371 .update("mock", new Mock())
1372 .setUp(
1373 "mykwargs = {'extraKey2':'x', 'named':True}",
1374 "b = mock.with_kwargs(True, extraKey1=True, **mykwargs)")
1375 .testLookup("b", "with_kwargs(true, true, kwargs(extraKey1=true, extraKey2=x))");
1376 }
1377
1378 @Test
1379 public void testJavaFunctionWithArgsAndKwargs() throws Exception {
1380 // Foo is used positionally
1381 new SkylarkTest()
1382 .update("mock", new Mock())
1383 .setUp("b = mock.with_args_and_kwargs('foo', 'bar', 'baz', extraKey1=True, extraKey2='x')")
1384 .testLookup(
1385 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey1=true, extraKey2=x))");
1386
1387 // Use an args list and a kwargs dict
1388 new SkylarkTest()
1389 .update("mock", new Mock())
1390 .setUp(
1391 "mykwargs = {'extraKey1':True}",
1392 "myargs = ['baz']",
1393 "b = mock.with_args_and_kwargs('foo', 'bar', extraKey2='x', *myargs, **mykwargs)")
1394 .testLookup(
1395 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey2=x, extraKey1=true))");
1396
1397 // Foo is used by name
1398 new SkylarkTest()
1399 .update("mock", new Mock())
1400 .setUp("b = mock.with_args_and_kwargs(foo='foo', extraKey1=True)")
1401 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs(extraKey1=true))");
1402
1403 // Empty args and kwargs.
1404 new SkylarkTest()
1405 .update("mock", new Mock())
1406 .setUp("b = mock.with_args_and_kwargs('foo')")
1407 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs())");
1408 }
1409
1410 @Test
1411 public void testProxyMethodsObjectWithArgsAndKwargs() throws Exception {
1412 // Foo is used positionally
1413 new SkylarkTest()
1414 .update("mock", new Mock())
1415 .setUp(
1416 "m = mock.proxy_methods_object()",
1417 "b = m.with_args_and_kwargs('foo', 'bar', 'baz', extraKey1=True, extraKey2='x')")
1418 .testLookup(
1419 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey1=true, extraKey2=x))");
1420
1421 // Use an args list and a kwargs dict
1422 new SkylarkTest()
1423 .update("mock", new Mock())
1424 .setUp(
1425 "mykwargs = {'extraKey1':True}",
1426 "myargs = ['baz']",
1427 "m = mock.proxy_methods_object()",
1428 "b = m.with_args_and_kwargs('foo', 'bar', extraKey2='x', *myargs, **mykwargs)")
1429 .testLookup(
1430 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey2=x, extraKey1=true))");
1431
1432 // Foo is used by name
1433 new SkylarkTest()
1434 .update("mock", new Mock())
1435 .setUp(
1436 "m = mock.proxy_methods_object()",
1437 "b = m.with_args_and_kwargs(foo='foo', extraKey1=True)")
1438 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs(extraKey1=true))");
1439
1440 // Empty args and kwargs.
1441 new SkylarkTest()
1442 .update("mock", new Mock())
1443 .setUp("m = mock.proxy_methods_object()", "b = m.with_args_and_kwargs('foo')")
1444 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs())");
1445 }
1446
1447 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001448 public void testStructAccessOfMethod() throws Exception {
Marwan Tammama7b2b112019-07-24 03:45:55 -07001449 new SkylarkTest().update("mock", new Mock()).testStatement("v = mock.function", null);
Laurent Le Brun57badf42017-01-02 15:12:24 +00001450 }
1451
1452 @Test
1453 public void testStructAccessTypo() throws Exception {
1454 new SkylarkTest()
1455 .update("mock", new MockClassObject())
1456 .testIfExactError(
1457 "object of type 'MockClassObject' has no field 'fild' (did you mean 'field'?)",
1458 "mock.fild");
Ulf Adams89f012d2015-02-26 13:39:28 +00001459 }
1460
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001461 @Test
Googler055d6c62018-05-22 13:21:04 -07001462 public void testStructAccessType_nonClassObject() throws Exception {
1463 new SkylarkTest()
1464 .update("mock", new Mock())
1465 .testIfExactError(
1466 "object of type 'Mock' has no field 'sturct_field' (did you mean 'struct_field'?)",
1467 "v = mock.sturct_field");
1468 }
1469
1470 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001471 public void testJavaFunctionReturnsMutableObject() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001472 new SkylarkTest()
1473 .update("mock", new Mock())
1474 .testIfExactError(
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001475 "method 'return_bad' returns an object of invalid type Bad", "mock.return_bad()");
Ulf Adams89f012d2015-02-26 13:39:28 +00001476 }
1477
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001478 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001479 public void testJavaFunctionReturnsNullFails() throws Exception {
Benjamin Petersonaf53a112019-06-05 10:47:11 -07001480 update("mock", new Mock());
1481 IllegalStateException e =
1482 assertThrows(IllegalStateException.class, () -> eval("mock.nullfunc_failing('abc', 1)"));
1483 assertThat(e).hasMessageThat().contains("method invocation returned None");
Ulf Adams89f012d2015-02-26 13:39:28 +00001484 }
1485
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001486 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001487 public void testClassObjectAccess() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001488 new SkylarkTest()
1489 .update("mock", new MockClassObject())
1490 .setUp("v = mock.field")
1491 .testLookup("v", "a");
Ulf Adams89f012d2015-02-26 13:39:28 +00001492 }
1493
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001494 @Test
laurentlb32282e52019-05-21 15:48:20 -07001495 public void testInSetDeprecated() throws Exception {
1496 new SkylarkTest("--incompatible_depset_is_not_iterable=false")
Vladimir Moskvad200daf2016-12-23 16:35:37 +00001497 .testStatement("'b' in depset(['a', 'b'])", Boolean.TRUE)
1498 .testStatement("'c' in depset(['a', 'b'])", Boolean.FALSE)
1499 .testStatement("1 in depset(['a', 'b'])", Boolean.FALSE);
Laurent Le Brunab0ca1a2015-03-31 17:13:25 +00001500 }
1501
1502 @Test
Laurent Le Brun092f13b2015-08-24 14:50:00 +00001503 public void testUnionSet() throws Exception {
laurentlb63c7ea62019-04-25 08:45:21 -07001504 new SkylarkTest("--incompatible_depset_union=false")
Vladimir Moskvaba4f0bb2017-01-30 15:45:49 +00001505 .testStatement("str(depset([1, 3]) | depset([1, 2]))", "depset([1, 2, 3])")
1506 .testStatement("str(depset([1, 2]) | [1, 3])", "depset([1, 2, 3])")
Laurent Le Brun092f13b2015-08-24 14:50:00 +00001507 .testIfExactError("unsupported operand type(s) for |: 'int' and 'int'", "2 | 4");
1508 }
1509
1510 @Test
laurentlbc9b6f4a2017-06-21 11:58:50 +02001511 public void testSetIsNotIterable() throws Exception {
1512 new SkylarkTest("--incompatible_depset_is_not_iterable=true")
1513 .testIfErrorContains("not iterable", "list(depset(['a', 'b']))")
1514 .testIfErrorContains("not iterable", "max(depset([1, 2, 3]))")
laurentlb0f5b7202017-06-23 16:55:01 +02001515 .testIfErrorContains("not iterable", "1 in depset([1, 2, 3])")
laurentlbc9b6f4a2017-06-21 11:58:50 +02001516 .testIfErrorContains("not iterable", "sorted(depset(['a', 'b']))")
1517 .testIfErrorContains("not iterable", "tuple(depset(['a', 'b']))")
laurentlbc32efc82017-06-23 16:03:00 +02001518 .testIfErrorContains("not iterable", "[x for x in depset()]")
1519 .testIfErrorContains("not iterable", "len(depset(['a']))");
laurentlbc9b6f4a2017-06-21 11:58:50 +02001520 }
1521
1522 @Test
1523 public void testSetIsIterable() throws Exception {
1524 new SkylarkTest("--incompatible_depset_is_not_iterable=false")
1525 .testStatement("str(list(depset(['a', 'b'])))", "[\"a\", \"b\"]")
1526 .testStatement("max(depset([1, 2, 3]))", 3)
laurentlb0f5b7202017-06-23 16:55:01 +02001527 .testStatement("1 in depset([1, 2, 3])", true)
laurentlbc9b6f4a2017-06-21 11:58:50 +02001528 .testStatement("str(sorted(depset(['b', 'a'])))", "[\"a\", \"b\"]")
1529 .testStatement("str(tuple(depset(['a', 'b'])))", "(\"a\", \"b\")")
laurentlbc32efc82017-06-23 16:03:00 +02001530 .testStatement("str([x for x in depset()])", "[]")
1531 .testStatement("len(depset(['a']))", 1);
laurentlbc9b6f4a2017-06-21 11:58:50 +02001532 }
1533
1534 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001535 public void testClassObjectCannotAccessNestedSet() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001536 new SkylarkTest()
1537 .update("mock", new MockClassObject())
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001538 .testIfErrorContains("internal error: type 'NestedSet' is not allowed", "v = mock.nset");
Ulf Adams89f012d2015-02-26 13:39:28 +00001539 }
1540
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001541 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001542 public void testJavaFunctionReturnsNone() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001543 new SkylarkTest()
1544 .update("mock", new Mock())
1545 .setUp("v = mock.nullfunc_working()")
Francois-Rene Rideau0f7ba342015-08-31 16:16:21 +00001546 .testLookup("v", Runtime.NONE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001547 }
1548
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001549 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001550 public void testVoidJavaFunctionReturnsNone() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001551 new SkylarkTest()
1552 .update("mock", new Mock())
1553 .setUp("v = mock.voidfunc()")
Francois-Rene Rideau0f7ba342015-08-31 16:16:21 +00001554 .testLookup("v", Runtime.NONE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001555 }
1556
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001557 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001558 public void testAugmentedAssignment() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001559 new SkylarkTest().setUp("def f1(x):",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001560 " x += 1",
1561 " return x",
1562 "",
Florian Weikert28da3652015-07-01 14:52:30 +00001563 "foo = f1(41)").testLookup("foo", 42);
Ulf Adams89f012d2015-02-26 13:39:28 +00001564 }
1565
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001566 @Test
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001567 public void testAugmentedAssignmentHasNoSideEffects() throws Exception {
brandjon2b51f782017-07-25 21:05:04 +02001568 // Check object position.
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001569 new SkylarkTest().setUp(
1570 "counter = [0]",
1571 "value = [1, 2]",
1572 "",
1573 "def f():",
1574 " counter[0] = counter[0] + 1",
1575 " return value",
1576 "",
1577 "f()[1] += 1") // `f()` should be called only once here
1578 .testLookup("counter", MutableList.of(env, 1));
brandjon2b51f782017-07-25 21:05:04 +02001579
1580 // Check key position.
1581 new SkylarkTest().setUp(
1582 "counter = [0]",
1583 "value = [1, 2]",
1584 "",
1585 "def f():",
1586 " counter[0] = counter[0] + 1",
1587 " return 1",
1588 "",
1589 "value[f()] += 1") // `f()` should be called only once here
1590 .testLookup("counter", MutableList.of(env, 1));
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001591 }
1592
1593 @Test
brandjon2b51f782017-07-25 21:05:04 +02001594 public void testInvalidAugmentedAssignment_ListLiteral() throws Exception {
laurentlbe3684492017-08-21 12:02:46 +02001595 new SkylarkTest().testIfErrorContains(
1596 "cannot perform augmented assignment on a list or tuple expression",
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001597 "def f(a, b):",
1598 " [a, b] += []",
1599 "f(1, 2)");
1600 }
1601
1602 @Test
brandjon2b51f782017-07-25 21:05:04 +02001603 public void testInvalidAugmentedAssignment_NotAnLValue() throws Exception {
1604 newTest().testIfErrorContains(
1605 "cannot assign to 'x + 1'", "x + 1 += 2");
1606 }
1607
1608 @Test
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001609 public void testAssignmentEvaluationOrder() throws Exception {
1610 new SkylarkTest().setUp(
1611 "ordinary = []",
1612 "augmented = []",
1613 "value = [1, 2]",
1614 "",
1615 "def f(record):",
1616 " record.append('f')",
1617 " return value",
1618 "",
1619 "def g(record):",
1620 " record.append('g')",
1621 " return value",
1622 "",
1623 "f(ordinary)[0] = g(ordinary)[1]",
1624 "f(augmented)[0] += g(augmented)[1]")
1625 .testLookup("ordinary", MutableList.of(env, "g", "f")) // This order is consistent
1626 .testLookup("augmented", MutableList.of(env, "f", "g")); // with Python
1627 }
1628
1629 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001630 public void testDictComprehensions_IterationOrder() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001631 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001632 " d = {x : x for x in ['c', 'a', 'b']}",
1633 " s = ''",
1634 " for a in d:",
1635 " s += a",
1636 " return s",
Vladimir Moskva76e31d12016-12-05 16:28:37 +00001637 "s = foo()").testLookup("s", "cab");
Ulf Adams89f012d2015-02-26 13:39:28 +00001638 }
1639
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001640 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001641 public void testDotExpressionOnNonStructObject() throws Exception {
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001642 new SkylarkTest()
Laurent Le Brun57badf42017-01-02 15:12:24 +00001643 .testIfExactError("object of type 'string' has no field 'field'", "x = 'a'.field");
Ulf Adams89f012d2015-02-26 13:39:28 +00001644 }
1645
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001646 @Test
vladmos25da19d2017-05-04 18:00:59 +02001647 public void testPlusEqualsOnListMutating() throws Exception {
vladmosc5301e92017-12-08 03:07:47 -08001648 new SkylarkTest()
vladmos25da19d2017-05-04 18:00:59 +02001649 .setUp(
1650 "def func():",
1651 " l1 = [1, 2]",
1652 " l2 = l1",
1653 " l2 += [3, 4]",
1654 " return l1, l2",
1655 "lists = str(func())")
1656 .testLookup("lists", "([1, 2, 3, 4], [1, 2, 3, 4])");
1657
1658 // The same but with += after an IndexExpression
vladmosc5301e92017-12-08 03:07:47 -08001659 new SkylarkTest()
vladmos25da19d2017-05-04 18:00:59 +02001660 .setUp(
1661 "def func():",
1662 " l = [1, 2]",
1663 " d = {0: l}",
1664 " d[0] += [3, 4]",
1665 " return l, d[0]",
1666 "lists = str(func())")
1667 .testLookup("lists", "([1, 2, 3, 4], [1, 2, 3, 4])");
1668 }
1669
1670 @Test
1671 public void testPlusEqualsOnTuple() throws Exception {
vladmosc5301e92017-12-08 03:07:47 -08001672 new SkylarkTest()
vladmos25da19d2017-05-04 18:00:59 +02001673 .setUp(
1674 "def func():",
1675 " t1 = (1, 2)",
1676 " t2 = t1",
1677 " t2 += (3, 4)",
1678 " return t1, t2",
1679 "tuples = func()")
1680 .testLookup("tuples", SkylarkList.Tuple.of(
1681 SkylarkList.Tuple.of(1, 2),
1682 SkylarkList.Tuple.of(1, 2, 3, 4)
1683 ));
1684 }
1685
1686 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001687 public void testPlusEqualsOnDict() throws Exception {
vladmos541afa62018-01-02 09:17:58 -08001688 new SkylarkTest("--incompatible_disallow_dict_plus=false").setUp("def func():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001689 " d = {'a' : 1}",
1690 " d += {'b' : 2}",
1691 " return d",
Florian Weikert28da3652015-07-01 14:52:30 +00001692 "d = func()")
1693 .testLookup("d", ImmutableMap.of("a", 1, "b", 2));
Ulf Adams89f012d2015-02-26 13:39:28 +00001694 }
1695
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001696 @Test
vladmosee0a8bb2017-05-04 19:26:48 +02001697 public void testPlusOnDictDeprecated() throws Exception {
brandjon2a9a1b72017-05-08 09:11:05 -04001698 new SkylarkTest("--incompatible_disallow_dict_plus=true")
vladmosee0a8bb2017-05-04 19:26:48 +02001699 .testIfErrorContains(
1700 "The `+` operator for dicts is deprecated and no longer supported.", "{1: 2} + {3: 4}");
brandjon2a9a1b72017-05-08 09:11:05 -04001701 new SkylarkTest("--incompatible_disallow_dict_plus=true")
vladmosee0a8bb2017-05-04 19:26:48 +02001702 .testIfErrorContains(
1703 "The `+` operator for dicts is deprecated and no longer supported.",
1704 "def func():",
1705 " d = {1: 2}",
1706 " d += {3: 4}",
1707 "func()");
1708 }
1709
1710 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001711 public void testDictAssignmentAsLValue() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001712 new SkylarkTest().setUp("def func():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001713 " d = {'a' : 1}",
1714 " d['b'] = 2",
1715 " return d",
Florian Weikert28da3652015-07-01 14:52:30 +00001716 "d = func()").testLookup("d", ImmutableMap.of("a", 1, "b", 2));
Ulf Adams89f012d2015-02-26 13:39:28 +00001717 }
1718
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001719 @Test
Vladimir Moskva10770382016-08-23 15:04:54 +00001720 public void testNestedDictAssignmentAsLValue() throws Exception {
1721 new SkylarkTest().setUp("def func():",
1722 " d = {'a' : 1}",
1723 " e = {'d': d}",
1724 " e['d']['b'] = 2",
1725 " return e",
1726 "e = func()").testLookup("e", ImmutableMap.of("d", ImmutableMap.of("a", 1, "b", 2)));
1727 }
1728
1729 @Test
1730 public void testListAssignmentAsLValue() throws Exception {
1731 new SkylarkTest().setUp("def func():",
1732 " a = [1, 2]",
1733 " a[1] = 3",
1734 " a[-2] = 4",
1735 " return a",
1736 "a = str(func())").testLookup("a", "[4, 3]");
1737 }
1738
1739 @Test
1740 public void testNestedListAssignmentAsLValue() throws Exception {
1741 new SkylarkTest().setUp("def func():",
1742 " d = [1, 2]",
1743 " e = [3, d]",
1744 " e[1][1] = 4",
1745 " return e",
1746 "e = str(func())").testLookup("e", "[3, [1, 4]]");
1747 }
cparsons6c1c0662018-02-05 02:01:28 -08001748
Vladimir Moskva10770382016-08-23 15:04:54 +00001749 @Test
Laurent Le Brund640bd32016-01-07 13:58:43 +00001750 public void testDictTupleAssignmentAsLValue() throws Exception {
1751 new SkylarkTest().setUp("def func():",
1752 " d = {'a' : 1}",
1753 " d['b'], d['c'] = 2, 3",
1754 " return d",
1755 "d = func()").testLookup("d", ImmutableMap.of("a", 1, "b", 2, "c", 3));
1756 }
1757
1758 @Test
1759 public void testDictItemPlusEqual() throws Exception {
1760 new SkylarkTest().setUp("def func():",
1761 " d = {'a' : 2}",
1762 " d['a'] += 3",
1763 " return d",
1764 "d = func()").testLookup("d", ImmutableMap.of("a", 5));
1765 }
1766
1767 @Test
Francois-Rene Rideauab049e02016-02-17 16:13:46 +00001768 public void testDictAssignmentAsLValueSideEffects() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001769 new SkylarkTest().setUp("def func(d):",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001770 " d['b'] = 2",
1771 "d = {'a' : 1}",
Francois-Rene Rideauab049e02016-02-17 16:13:46 +00001772 "func(d)").testLookup("d", SkylarkDict.of(null, "a", 1, "b", 2));
Ulf Adams89f012d2015-02-26 13:39:28 +00001773 }
1774
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001775 @Test
Francois-Rene Rideauef7a8a52016-01-29 17:37:48 +00001776 public void testAssignmentToListInDictSideEffect() throws Exception {
1777 new SkylarkTest().setUp(
1778 "l = [1, 2]",
1779 "d = {0: l}",
1780 "d[0].append(3)").testLookup("l", MutableList.of(null, 1, 2, 3));
1781 }
1782
1783 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001784 public void testUserFunctionKeywordArgs() throws Exception {
Francois-Rene Rideau676905a2015-08-31 15:39:09 +00001785 new SkylarkTest().setUp("def foo(a, b, c):",
Florian Weikert28da3652015-07-01 14:52:30 +00001786 " return a + b + c", "s = foo(1, c=2, b=3)")
1787 .testLookup("s", 6);
Ulf Adams89f012d2015-02-26 13:39:28 +00001788 }
1789
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001790 @Test
Laurent Le Brun68743162015-05-13 13:18:09 +00001791 public void testFunctionCallOrdering() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001792 new SkylarkTest().setUp("def func(): return foo() * 2",
Laurent Le Brun68743162015-05-13 13:18:09 +00001793 "def foo(): return 2",
Florian Weikert28da3652015-07-01 14:52:30 +00001794 "x = func()")
1795 .testLookup("x", 4);
Laurent Le Brun68743162015-05-13 13:18:09 +00001796 }
1797
1798 @Test
1799 public void testFunctionCallBadOrdering() throws Exception {
laurentlb3f4ee542018-09-11 05:41:26 -07001800 new SkylarkTest()
1801 .testIfErrorContains(
laurentlb3a979f72018-11-20 07:25:11 -08001802 "global variable 'foo' is referenced before assignment.",
laurentlb3f4ee542018-09-11 05:41:26 -07001803 "def func(): return foo() * 2",
1804 "x = func()",
1805 "def foo(): return 2");
Laurent Le Brun68743162015-05-13 13:18:09 +00001806 }
1807
1808 @Test
laurentlbcaafe302018-08-28 10:24:31 -07001809 public void testLocalVariableDefinedBelow() throws Exception {
laurentlb3f4ee542018-09-11 05:41:26 -07001810 new SkylarkTest()
laurentlbcaafe302018-08-28 10:24:31 -07001811 .setUp(
1812 "def beforeEven(li):", // returns the value before the first even number
1813 " for i in li:",
1814 " if i % 2 == 0:",
1815 " return a",
1816 " else:",
1817 " a = i",
1818 "res = beforeEven([1, 3, 4, 5])")
1819 .testLookup("res", 3);
1820 }
1821
1822 @Test
1823 public void testShadowisNotInitialized() throws Exception {
laurentlb2b3ad182018-12-05 05:49:45 -08001824 new SkylarkTest()
laurentlbcaafe302018-08-28 10:24:31 -07001825 .testIfErrorContains(
laurentlbebb40712018-08-29 11:54:27 -07001826 /* error message */ "local variable 'gl' is referenced before assignment",
laurentlbcaafe302018-08-28 10:24:31 -07001827 "gl = 5",
laurentlb3f4ee542018-09-11 05:41:26 -07001828 "def foo():",
laurentlbcaafe302018-08-28 10:24:31 -07001829 " if False: gl = 2",
1830 " return gl",
1831 "res = foo()");
1832 }
1833
1834 @Test
laurentlb3f4ee542018-09-11 05:41:26 -07001835 public void testShadowBuiltin() throws Exception {
laurentlb2b3ad182018-12-05 05:49:45 -08001836 new SkylarkTest()
laurentlbf6350622018-09-19 10:15:34 -07001837 .testIfErrorContains(
1838 "global variable 'len' is referenced before assignment",
1839 "x = len('abc')",
1840 "len = 2",
1841 "y = x + len");
1842 }
1843
1844 @Test
brandjon65fd1362017-10-22 19:49:35 +02001845 public void testFunctionCallRecursion() throws Exception {
1846 new SkylarkTest().testIfErrorContains("Recursion was detected when calling 'f' from 'g'",
1847 "def main():",
1848 " f(5)",
1849 "def f(n):",
1850 " if n > 0: g(n - 1)",
1851 "def g(n):",
1852 " if n > 0: f(n - 1)",
1853 "main()");
1854 }
1855
1856 @Test
Laurent Le Brune102a2d2017-01-02 12:06:18 +00001857 public void testTypo() throws Exception {
1858 new SkylarkTest()
1859 .testIfErrorContains(
1860 "name 'my_variable' is not defined (did you mean 'myVariable'?)",
1861 "myVariable = 2",
1862 "x = my_variable + 1");
1863 }
1864
1865 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001866 public void testNoneTrueFalseInSkylark() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001867 new SkylarkTest().setUp("a = None",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001868 "b = True",
Florian Weikert28da3652015-07-01 14:52:30 +00001869 "c = False")
Francois-Rene Rideau0f7ba342015-08-31 16:16:21 +00001870 .testLookup("a", Runtime.NONE)
Florian Weikert28da3652015-07-01 14:52:30 +00001871 .testLookup("b", Boolean.TRUE)
1872 .testLookup("c", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001873 }
1874
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001875 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001876 public void testHasattrMethods() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001877 new SkylarkTest()
1878 .update("mock", new Mock())
1879 .setUp("a = hasattr(mock, 'struct_field')", "b = hasattr(mock, 'function')",
1880 "c = hasattr(mock, 'is_empty')", "d = hasattr('str', 'replace')",
1881 "e = hasattr(mock, 'other')\n")
1882 .testLookup("a", Boolean.TRUE)
1883 .testLookup("b", Boolean.TRUE)
1884 .testLookup("c", Boolean.TRUE)
1885 .testLookup("d", Boolean.TRUE)
1886 .testLookup("e", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001887 }
1888
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001889 @Test
cparsonse70aafe2018-02-28 12:16:38 -08001890 public void testGetattrMethods() throws Exception {
1891 new SkylarkTest()
1892 .update("mock", new Mock())
Marwan Tammama7b2b112019-07-24 03:45:55 -07001893 .setUp(
1894 "a = str(getattr(mock, 'struct_field', 'no'))",
1895 "b = str(getattr(mock, 'function', 'no'))",
1896 "c = str(getattr(mock, 'is_empty', 'no'))",
1897 "d = str(getattr('str', 'replace', 'no'))",
1898 "e = str(getattr(mock, 'other', 'no'))\n")
cparsonse70aafe2018-02-28 12:16:38 -08001899 .testLookup("a", "a")
Marwan Tammama7b2b112019-07-24 03:45:55 -07001900 .testLookup("b", "<built-in function function>")
1901 .testLookup("c", "<built-in function is_empty>")
1902 .testLookup("d", "<built-in function replace>")
cparsonse70aafe2018-02-28 12:16:38 -08001903 .testLookup("e", "no");
1904 }
1905
1906 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001907 public void testListAnTupleConcatenationDoesNotWorkInSkylark() throws Exception {
Francois-Rene Rideau93ed7f12015-10-20 15:39:33 +00001908 new SkylarkTest().testIfExactError("unsupported operand type(s) for +: 'list' and 'tuple'",
Francois-Rene Rideau4e994102015-09-17 22:41:28 +00001909 "[1, 2] + (3, 4)");
Ulf Adams89f012d2015-02-26 13:39:28 +00001910 }
1911
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001912 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001913 public void testCannotCreateMixedListInSkylark() throws Exception {
Laurent Le Brune083a912015-08-10 15:13:34 +00001914 new SkylarkTest().testExactOrder("['a', 'b', 1, 2]", "a", "b", 1, 2);
Ulf Adams89f012d2015-02-26 13:39:28 +00001915 }
1916
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001917 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001918 public void testCannotConcatListInSkylarkWithDifferentGenericTypes() throws Exception {
Laurent Le Brune083a912015-08-10 15:13:34 +00001919 new SkylarkTest().testExactOrder("[1, 2] + ['a', 'b']", 1, 2, "a", "b");
Ulf Adams89f012d2015-02-26 13:39:28 +00001920 }
1921
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001922 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001923 public void testConcatEmptyListWithNonEmptyWorks() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001924 new SkylarkTest().testExactOrder("[] + ['a', 'b']", "a", "b");
Ulf Adams89f012d2015-02-26 13:39:28 +00001925 }
1926
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001927 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001928 public void testFormatStringWithTuple() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001929 new SkylarkTest().setUp("v = '%s%s' % ('a', 1)").testLookup("v", "a1");
Ulf Adams89f012d2015-02-26 13:39:28 +00001930 }
1931
Francois-Rene Rideaue8cfead2015-03-17 16:01:47 +00001932 @Test
1933 public void testSingletonTuple() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001934 new SkylarkTest().testExactOrder("(1,)", 1);
Francois-Rene Rideaue8cfead2015-03-17 16:01:47 +00001935 }
1936
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001937 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001938 public void testDirFindsClassObjectFields() throws Exception {
Laurent Le Brun8e965b82016-08-03 11:50:24 +00001939 new SkylarkTest().update("mock", new MockClassObject())
Florian Weikert28da3652015-07-01 14:52:30 +00001940 .testExactOrder("dir(mock)", "field", "nset");
Ulf Adams89f012d2015-02-26 13:39:28 +00001941 }
1942
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001943 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001944 public void testDirFindsJavaObjectStructFieldsAndMethods() throws Exception {
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001945 new SkylarkTest()
1946 .update("mock", new Mock())
1947 .testExactOrder(
1948 "dir(mock)",
1949 "function",
Benjamin Petersonbf1db782018-08-08 10:03:22 -07001950 "interrupted_struct_field",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001951 "is_empty",
cparsons4baafac2018-04-11 11:09:17 -07001952 "legacy_method",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001953 "nullfunc_failing",
1954 "nullfunc_working",
cparsons7520dcc2018-04-04 13:59:27 -07001955 "proxy_methods_object",
Benjamin Petersonaf53a112019-06-05 10:47:11 -07001956 "raise_unchecked_exception",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001957 "return_bad",
1958 "string",
1959 "string_list",
cparsonsaaab11f2018-01-31 11:00:11 -08001960 "string_list_dict",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001961 "struct_field",
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001962 "struct_field_callable",
cparsons07460fc2018-06-20 10:41:48 -07001963 "struct_field_with_extra",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001964 "value_of",
1965 "voidfunc",
cparsons979195e2018-04-09 15:43:22 -07001966 "with_args_and_env",
1967 "with_args_and_kwargs",
cparsons5d446a72018-03-07 11:01:17 -08001968 "with_extra",
cparsons979195e2018-04-09 15:43:22 -07001969 "with_kwargs",
cparsons5d446a72018-03-07 11:01:17 -08001970 "with_params",
1971 "with_params_and_extra");
Ulf Adams89f012d2015-02-26 13:39:28 +00001972 }
1973
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001974 @Test
cparsons6c1c0662018-02-05 02:01:28 -08001975 public void testStrNativeInfo() throws Exception {
1976 new SkylarkTest()
1977 .update("mock", new NativeInfoMock())
1978 .testEval(
1979 "str(mock)",
1980 "'struct(struct_field_callable = <built-in function foobar>, struct_field_none = None, "
1981 + "struct_field_string = \"a\")'");
1982 }
1983
1984 @Test
1985 public void testDirNativeInfo() throws Exception {
1986 new SkylarkTest()
1987 .update("mock", new NativeInfoMock())
1988 .testEval(
1989 "dir(mock)",
cparsons63c25552018-04-10 13:36:29 -07001990 "['callable_string', 'struct_field_callable', 'struct_field_none', "
1991 + "'struct_field_string', 'to_json', 'to_proto']");
cparsons6c1c0662018-02-05 02:01:28 -08001992 }
1993
1994 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001995 public void testPrint() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001996 // TODO(fwe): cannot be handled by current testing suite
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001997 setFailFast(false);
1998 eval("print('hello')");
vladmosa664a512017-08-10 20:30:17 +02001999 assertContainsDebug("hello");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002000 eval("print('a', 'b')");
vladmosa664a512017-08-10 20:30:17 +02002001 assertContainsDebug("a b");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002002 eval("print('a', 'b', sep='x')");
vladmosa664a512017-08-10 20:30:17 +02002003 assertContainsDebug("axb");
Ulf Adams89f012d2015-02-26 13:39:28 +00002004 }
2005
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00002006 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00002007 public void testPrintBadKwargs() throws Exception {
cparsons7ac265d2019-04-16 15:31:17 -07002008 new SkylarkTest()
2009 .testIfErrorContains(
2010 "unexpected keywords 'end', 'other', for call to function print(sep = \" \", *args)",
2011 "print(end='x', other='y')");
Ulf Adams89f012d2015-02-26 13:39:28 +00002012 }
2013
Ulf Adams89f012d2015-02-26 13:39:28 +00002014 // Override tests in EvaluationTest incompatible with Skylark
2015
2016 @SuppressWarnings("unchecked")
2017 @Override
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00002018 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00002019 public void testConcatLists() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00002020 new SkylarkTest().testExactOrder("[1,2] + [3,4]", 1, 2, 3, 4).testExactOrder("(1,2)", 1, 2)
2021 .testExactOrder("(1,2) + (3,4)", 1, 2, 3, 4);
2022
2023 // TODO(fwe): cannot be handled by current testing suite
Ulf Adams89f012d2015-02-26 13:39:28 +00002024 // list
2025 Object x = eval("[1,2] + [3,4]");
2026 assertThat((Iterable<Object>) x).containsExactly(1, 2, 3, 4).inOrder();
Ulf Adams89f012d2015-02-26 13:39:28 +00002027
2028 // tuple
2029 x = eval("(1,2)");
2030 assertThat((Iterable<Object>) x).containsExactly(1, 2).inOrder();
lberkiaea56b32017-05-30 12:35:33 +02002031 assertThat(((SkylarkList) x).isTuple()).isTrue();
Ulf Adams89f012d2015-02-26 13:39:28 +00002032
2033 x = eval("(1,2) + (3,4)");
2034 assertThat((Iterable<Object>) x).containsExactly(1, 2, 3, 4).inOrder();
lberkiaea56b32017-05-30 12:35:33 +02002035 assertThat(((SkylarkList) x).isTuple()).isTrue();
Ulf Adams89f012d2015-02-26 13:39:28 +00002036 }
2037
Ulf Adams89f012d2015-02-26 13:39:28 +00002038 @Override
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00002039 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00002040 public void testListConcatenation() throws Exception {}
2041
Florian Weikertf07e5442015-07-01 13:08:43 +00002042 @Override
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002043 @Test
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002044 public void testListComprehensionsMultipleVariablesFail() throws Exception {
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002045 new SkylarkTest()
2046 .testIfErrorContains(
brandjon2b51f782017-07-25 21:05:04 +02002047 "assignment length mismatch: left-hand side has length 3, but right-hand side "
2048 + "evaluates to value of length 2",
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002049 "def foo (): return [x + y for x, y, z in [(1, 2), (3, 4)]]",
2050 "foo()");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002051
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002052 new SkylarkTest()
2053 .testIfErrorContains(
2054 "type 'int' is not a collection",
2055 "def bar (): return [x + y for x, y in (1, 2)]",
2056 "bar()");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002057
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002058 new SkylarkTest()
2059 .testIfErrorContains(
brandjon2b51f782017-07-25 21:05:04 +02002060 "assignment length mismatch: left-hand side has length 3, but right-hand side "
2061 + "evaluates to value of length 2",
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002062 "[x + y for x, y, z in [(1, 2), (3, 4)]]");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002063
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002064 new SkylarkTest()
2065 .testIfErrorContains("type 'int' is not a collection", "[x2 + y2 for x2, y2 in (1, 2)]");
laurentlb2db52702017-07-05 14:19:22 -04002066
2067 new SkylarkTest()
2068 // returns [2] in Python, it's an error in Skylark
brandjon2b51f782017-07-25 21:05:04 +02002069 .testIfErrorContains("must have at least one item", "[2 for [] in [()]]");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002070 }
2071
2072 @Override
2073 @Test
2074 public void testNotCallInt() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00002075 new SkylarkTest().setUp("sum = 123456").testLookup("sum", 123456)
2076 .testIfExactError("'int' object is not callable", "sum(1, 2, 3, 4, 5, 6)")
2077 .testStatement("sum", 123456);
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002078 }
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +00002079
2080 @Test
2081 public void testConditionalExpressionAtToplevel() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00002082 new SkylarkTest().setUp("x = 1 if 2 else 3").testLookup("x", 1);
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +00002083 }
2084
2085 @Test
2086 public void testConditionalExpressionInFunction() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00002087 new SkylarkTest().setUp("def foo(a, b, c): return a+b if c else a-b\n").testStatement(
2088 "foo(23, 5, 0)", 18);
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +00002089 }
Michael Staib79bd2c22017-03-22 14:37:03 +00002090
2091 @SkylarkModule(name = "SkylarkClassObjectWithSkylarkCallables", doc = "")
dslomovf1296572017-08-22 16:29:06 +02002092 static final class SkylarkClassObjectWithSkylarkCallables extends NativeInfo {
dslomovde965ac2017-07-31 21:07:51 +02002093 private static final NativeProvider<SkylarkClassObjectWithSkylarkCallables> CONSTRUCTOR =
2094 new NativeProvider<SkylarkClassObjectWithSkylarkCallables>(
2095 SkylarkClassObjectWithSkylarkCallables.class, "struct_with_skylark_callables") {};
Michael Staib79bd2c22017-03-22 14:37:03 +00002096
2097 SkylarkClassObjectWithSkylarkCallables() {
2098 super(
2099 CONSTRUCTOR,
2100 ImmutableMap.of(
2101 "values_only_field",
2102 "fromValues",
2103 "values_only_method",
2104 new BuiltinFunction("values_only_method", FunctionSignature.of()) {
2105 public String invoke() {
2106 return "fromValues";
2107 }
2108 },
2109 "collision_field",
2110 "fromValues",
2111 "collision_method",
2112 new BuiltinFunction("collision_method", FunctionSignature.of()) {
2113 public String invoke() {
2114 return "fromValues";
2115 }
cparsonse70aafe2018-02-28 12:16:38 -08002116 }),
2117 Location.BUILTIN);
Michael Staib79bd2c22017-03-22 14:37:03 +00002118 }
2119
cparsons7f475d72018-03-30 13:54:46 -07002120 @SkylarkCallable(name = "callable_only_field", documented = false, structField = true)
Michael Staib79bd2c22017-03-22 14:37:03 +00002121 public String getCallableOnlyField() {
2122 return "fromSkylarkCallable";
2123 }
2124
cparsons7f475d72018-03-30 13:54:46 -07002125 @SkylarkCallable(name = "callable_only_method", documented = false, structField = false)
Michael Staib79bd2c22017-03-22 14:37:03 +00002126 public String getCallableOnlyMethod() {
2127 return "fromSkylarkCallable";
2128 }
2129
cparsons7f475d72018-03-30 13:54:46 -07002130 @SkylarkCallable(name = "collision_field", documented = false, structField = true)
Michael Staib79bd2c22017-03-22 14:37:03 +00002131 public String getCollisionField() {
2132 return "fromSkylarkCallable";
2133 }
2134
cparsons7f475d72018-03-30 13:54:46 -07002135 @SkylarkCallable(name = "collision_method", documented = false, structField = false)
Michael Staib79bd2c22017-03-22 14:37:03 +00002136 public String getCollisionMethod() {
2137 return "fromSkylarkCallable";
2138 }
2139 }
2140
2141 @Test
2142 public void testStructFieldDefinedOnlyInValues() throws Exception {
2143 new SkylarkTest()
2144 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2145 .setUp("v = val.values_only_field")
2146 .testLookup("v", "fromValues");
2147 }
2148
2149 @Test
2150 public void testStructMethodDefinedOnlyInValues() throws Exception {
2151 new SkylarkTest()
2152 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2153 .setUp("v = val.values_only_method()")
2154 .testLookup("v", "fromValues");
2155 }
2156
2157 @Test
2158 public void testStructFieldDefinedOnlyInSkylarkCallable() throws Exception {
2159 new SkylarkTest()
2160 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2161 .setUp("v = val.callable_only_field")
2162 .testLookup("v", "fromSkylarkCallable");
2163 }
2164
2165 @Test
2166 public void testStructMethodDefinedOnlyInSkylarkCallable() throws Exception {
2167 new SkylarkTest()
2168 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2169 .setUp("v = val.callable_only_method()")
2170 .testLookup("v", "fromSkylarkCallable");
2171 }
2172
2173 @Test
Michael Staib79bd2c22017-03-22 14:37:03 +00002174 public void testStructMethodDefinedInValuesAndSkylarkCallable() throws Exception {
2175 new SkylarkTest()
2176 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2177 .setUp("v = val.collision_method()")
cparsonsda392932018-11-02 16:04:13 -07002178 .testLookup("v", "fromSkylarkCallable");
Michael Staib79bd2c22017-03-22 14:37:03 +00002179 }
2180
2181 @Test
2182 public void testStructFieldNotDefined() throws Exception {
2183 new SkylarkTest()
2184 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2185 .testIfExactError(
cparsons6c1c0662018-02-05 02:01:28 -08002186 // TODO(bazel-team): This should probably list callable_only_method as well.
Michael Staib79bd2c22017-03-22 14:37:03 +00002187 "'struct_with_skylark_callables' object has no attribute 'nonexistent_field'\n"
cparsons6c1c0662018-02-05 02:01:28 -08002188 + "Available attributes: callable_only_field, collision_field, collision_method, "
2189 + "values_only_field, values_only_method",
Michael Staib79bd2c22017-03-22 14:37:03 +00002190 "v = val.nonexistent_field");
2191 }
2192
2193 @Test
2194 public void testStructMethodNotDefined() throws Exception {
2195 new SkylarkTest()
2196 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2197 .testIfExactError(
2198 // TODO(bazel-team): This should probably match the error above better.
cparsons71b4dcc2018-10-24 13:46:37 -07002199 "type 'SkylarkClassObjectWithSkylarkCallables' has no method nonexistent_method()",
2200 "v = val.nonexistent_method()");
Michael Staib79bd2c22017-03-22 14:37:03 +00002201 }
laurentlb9d5c0a02017-06-13 23:08:06 +02002202
2203 @Test
2204 public void testListComprehensionsDoNotLeakVariables() throws Exception {
laurentlb9d5c0a02017-06-13 23:08:06 +02002205 checkEvalErrorContains(
laurentlb3a979f72018-11-20 07:25:11 -08002206 // TODO(laurentlb): This happens because the variable gets undefined after the list
2207 // comprehension. We should do better.
2208 "local variable 'a' is referenced before assignment.",
laurentlb9d5c0a02017-06-13 23:08:06 +02002209 "def foo():",
2210 " a = 10",
2211 " b = [a for a in range(3)]",
2212 " return a",
2213 "x = foo()");
2214 }
2215
2216 @Test
2217 public void testListComprehensionsShadowGlobalVariable() throws Exception {
laurentlb9d5c0a02017-06-13 23:08:06 +02002218 eval("a = 18", "def foo():", " b = [a for a in range(3)]", " return a", "x = foo()");
2219 assertThat(lookup("x")).isEqualTo(18);
2220 }
2221
2222 @Test
laurentlbba69b392017-06-14 15:32:41 +02002223 public void testLoadStatementWithAbsolutePath() throws Exception {
laurentlbba69b392017-06-14 15:32:41 +02002224 checkEvalErrorContains(
Googler5b05b8a2018-11-05 23:54:03 -08002225 "First argument of 'load' must be a label and start with either '//', ':', or '@'",
laurentlb43336922019-04-15 08:04:07 -07002226 "load('/tmp/foo.bzl', 'arg')");
Kevin Gessnerb864db22017-09-06 20:14:49 +02002227 }
2228
2229 @Test
laurentlbba69b392017-06-14 15:32:41 +02002230 public void testLoadStatementWithRelativePath() throws Exception {
laurentlbba69b392017-06-14 15:32:41 +02002231 checkEvalErrorContains(
Googler5b05b8a2018-11-05 23:54:03 -08002232 "First argument of 'load' must be a label and start with either '//', ':', or '@'",
laurentlb43336922019-04-15 08:04:07 -07002233 "load('foo.bzl', 'arg')");
laurentlbba69b392017-06-14 15:32:41 +02002234 }
Kevin Gessnerb864db22017-09-06 20:14:49 +02002235
2236 @Test
Kevin Gessnerb864db22017-09-06 20:14:49 +02002237 public void testLoadStatementWithExternalLabel() throws Exception {
Kevin Gessnerb864db22017-09-06 20:14:49 +02002238 checkEvalErrorDoesNotContain(
Googler5b05b8a2018-11-05 23:54:03 -08002239 "First argument of 'load' must be a label and start with either '//', ':', or '@'",
Kevin Gessnerb864db22017-09-06 20:14:49 +02002240 "load('@other//foo.bzl', 'arg')");
2241 }
2242
2243 @Test
2244 public void testLoadStatementWithAbsoluteLabel() throws Exception {
Kevin Gessnerb864db22017-09-06 20:14:49 +02002245 checkEvalErrorDoesNotContain(
Googler5b05b8a2018-11-05 23:54:03 -08002246 "First argument of 'load' must be a label and start with either '//', ':', or '@'",
Kevin Gessnerb864db22017-09-06 20:14:49 +02002247 "load('//foo.bzl', 'arg')");
2248 }
2249
2250 @Test
2251 public void testLoadStatementWithRelativeLabel() throws Exception {
Kevin Gessnerb864db22017-09-06 20:14:49 +02002252 checkEvalErrorDoesNotContain(
Googler5b05b8a2018-11-05 23:54:03 -08002253 "First argument of 'load' must be a label and start with either '//', ':', or '@'",
Kevin Gessnerb864db22017-09-06 20:14:49 +02002254 "load(':foo.bzl', 'arg')");
2255 }
cparsons645a35e2018-10-01 13:03:23 -07002256
2257 @Test
2258 public void testAnalysisFailureInfo() throws Exception {
2259 AnalysisFailure cause = new AnalysisFailure(Label.create("test", "test"), "ErrorMessage");
2260
cparsonse8d450c2018-10-04 16:01:53 -07002261 AnalysisFailureInfo info = AnalysisFailureInfo.forAnalysisFailures(ImmutableList.of(cause));
cparsons645a35e2018-10-01 13:03:23 -07002262
cparsons8ec36392018-11-19 11:16:26 -08002263 new SkylarkTest()
cparsons645a35e2018-10-01 13:03:23 -07002264 .update("val", info)
2265 .setUp(
2266 "causes = val.causes",
2267 "label = causes.to_list()[0].label",
2268 "message = causes.to_list()[0].message")
2269 .testLookup("label", Label.create("test", "test"))
2270 .testLookup("message", "ErrorMessage");
cparsons645a35e2018-10-01 13:03:23 -07002271 }
cparsons6622e6f2018-10-17 15:00:09 -07002272
2273 @Test
2274 public void testExperimentalFlagGuardedValue() throws Exception {
2275 // This test uses an arbitrary experimental flag to verify this functionality. If this
2276 // experimental flag were to go away, this test may be updated to use any experimental flag.
2277 // The flag itself is unimportant to the test.
cparsons8ec36392018-11-19 11:16:26 -08002278 FlagGuardedValue val =
2279 FlagGuardedValue.onlyWhenExperimentalFlagIsTrue(
2280 FlagIdentifier.EXPERIMENTAL_BUILD_SETTING_API, "foo");
2281 String errorMessage =
2282 "GlobalSymbol is experimental and thus unavailable with the current "
2283 + "flags. It may be enabled by setting --experimental_build_setting_api";
cparsons6622e6f2018-10-17 15:00:09 -07002284
cparsons8ec36392018-11-19 11:16:26 -08002285 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=true")
cparsons6622e6f2018-10-17 15:00:09 -07002286 .setUp("var = GlobalSymbol")
2287 .testLookup("var", "foo");
2288
cparsons8ec36392018-11-19 11:16:26 -08002289 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=false")
2290 .testIfErrorContains(errorMessage, "var = GlobalSymbol");
cparsons6622e6f2018-10-17 15:00:09 -07002291
cparsons8ec36392018-11-19 11:16:26 -08002292 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=false")
2293 .testIfErrorContains(errorMessage, "def my_function():", " var = GlobalSymbol");
cparsons6622e6f2018-10-17 15:00:09 -07002294
cparsons8ec36392018-11-19 11:16:26 -08002295 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=false")
2296 .setUp("GlobalSymbol = 'other'", "var = GlobalSymbol")
cparsons6622e6f2018-10-17 15:00:09 -07002297 .testLookup("var", "other");
2298 }
2299
2300 @Test
2301 public void testIncompatibleFlagGuardedValue() throws Exception {
2302 // This test uses an arbitrary incompatible flag to verify this functionality. If this
2303 // incompatible flag were to go away, this test may be updated to use any incompatible flag.
2304 // The flag itself is unimportant to the test.
2305 FlagGuardedValue val = FlagGuardedValue.onlyWhenIncompatibleFlagIsFalse(
2306 FlagIdentifier.INCOMPATIBLE_NO_TARGET_OUTPUT_GROUP,
2307 "foo");
2308 String errorMessage = "GlobalSymbol is deprecated and will be removed soon. It may be "
2309 + "temporarily re-enabled by setting --incompatible_no_target_output_group=false";
2310
2311 new SkylarkTest(
2312 ImmutableMap.of("GlobalSymbol", val),
2313 "--incompatible_no_target_output_group=false")
2314 .setUp("var = GlobalSymbol")
2315 .testLookup("var", "foo");
2316
2317 new SkylarkTest(
2318 ImmutableMap.of("GlobalSymbol", val),
2319 "--incompatible_no_target_output_group=true")
2320 .testIfErrorContains(errorMessage,
2321 "var = GlobalSymbol");
2322
2323 new SkylarkTest(
2324 ImmutableMap.of("GlobalSymbol", val),
2325 "--incompatible_no_target_output_group=true")
2326 .testIfErrorContains(errorMessage,
2327 "def my_function():",
2328 " var = GlobalSymbol");
2329
2330 new SkylarkTest(
2331 ImmutableMap.of("GlobalSymbol", val),
2332 "--incompatible_no_target_output_group=true")
2333 .setUp("GlobalSymbol = 'other'",
2334 "var = GlobalSymbol")
2335 .testLookup("var", "other");
2336 }
Ulf Adams89f012d2015-02-26 13:39:28 +00002337}