blob: 10b5472cc851dbbbca80cdce2351984bbf2f9928 [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;
adonovan7202d102019-12-09 13:58:57 -080023import com.google.common.collect.ImmutableSet;
cparsons645a35e2018-10-01 13:03:23 -070024import com.google.devtools.build.lib.analysis.test.AnalysisFailure;
25import com.google.devtools.build.lib.analysis.test.AnalysisFailureInfo;
26import com.google.devtools.build.lib.cmdline.Label;
Ulf Adams89f012d2015-02-26 13:39:28 +000027import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
dslomov423dccc2017-04-11 12:18:09 +000028import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
cparsonse70aafe2018-02-28 12:16:38 -080029import com.google.devtools.build.lib.events.Location;
dslomovf1296572017-08-22 16:29:06 +020030import com.google.devtools.build.lib.packages.NativeInfo;
dslomovde965ac2017-07-31 21:07:51 +020031import com.google.devtools.build.lib.packages.NativeProvider;
cparsons0c5c1c62018-05-24 10:37:03 -070032import com.google.devtools.build.lib.packages.StructProvider;
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +000033import com.google.devtools.build.lib.skylarkinterface.Param;
Dmitry Lomovd22e1de2017-09-25 08:53:50 -040034import com.google.devtools.build.lib.skylarkinterface.ParamType;
John Field585d1a02015-12-16 16:03:52 +000035import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
Googlerab3cadc2019-11-08 15:17:21 -080036import com.google.devtools.build.lib.skylarkinterface.SkylarkGlobalLibrary;
John Field585d1a02015-12-16 16:03:52 +000037import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
laurentlb6659b4c2019-02-18 07:23:36 -080038import com.google.devtools.build.lib.syntax.StarlarkSemantics.FlagIdentifier;
Florian Weikert28da3652015-07-01 14:52:30 +000039import com.google.devtools.build.lib.testutil.TestMode;
cparsonsaaab11f2018-01-31 11:00:11 -080040import java.util.List;
41import java.util.Map;
Han-Wen Nienhuys33ce2112015-09-25 14:25:38 +000042import org.junit.Before;
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000043import org.junit.Test;
44import org.junit.runner.RunWith;
45import org.junit.runners.JUnit4;
46
Googlerbb0d36a2019-09-26 13:19:28 -070047/** Tests of Starlark evaluation. */
Googlerf0890f02019-10-01 07:28:48 -070048// This test uses 'extends' to make a copy of EvaluationTest whose
49// mode is overridden to SKYLARK, changing various environmental parameters.
Googlerab3cadc2019-11-08 15:17:21 -080050@SkylarkGlobalLibrary // required for @SkylarkCallable-annotated methods
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000051@RunWith(JUnit4.class)
Googlerf0890f02019-10-01 07:28:48 -070052public final class SkylarkEvaluationTest extends EvaluationTest {
Florian Weikertb4c59042015-12-01 10:47:18 +000053
Han-Wen Nienhuys33ce2112015-09-25 14:25:38 +000054 @Before
Florian Weikertb4c59042015-12-01 10:47:18 +000055 public final void setup() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +000056 setMode(TestMode.SKYLARK);
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000057 }
58
Florian Weikert28da3652015-07-01 14:52:30 +000059 /**
60 * Creates an instance of {@code SkylarkTest} in order to run the tests from the base class in a
61 * Skylark context
62 */
63 @Override
vladmos6ff634d2017-07-05 10:25:01 -040064 protected ModalTestCase newTest(String... skylarkOptions) {
65 return new SkylarkTest(skylarkOptions);
Florian Weikert28da3652015-07-01 14:52:30 +000066 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +000067
dslomov423dccc2017-04-11 12:18:09 +000068 @Immutable
Francois-Rene Rideau6c10eac2015-09-17 19:17:20 +000069 static class Bad {
70 Bad () {
71 }
72 }
73
Googlerab3cadc2019-11-08 15:17:21 -080074 @SkylarkCallable(name = "foobar", documented = false)
75 public String foobar() {
76 return "foobar";
77 }
Vladimir Moskvaa5b16742016-10-31 14:09:41 +000078
Googlerab3cadc2019-11-08 15:17:21 -080079 @SkylarkCallable(name = "interrupted_function", documented = false)
Googler641bdf72019-11-12 10:32:26 -080080 public NoneType interruptedFunction() throws InterruptedException {
Googlerab3cadc2019-11-08 15:17:21 -080081 throw new InterruptedException();
82 }
83
84 private static final NativeProvider<NativeInfoMock> CONSTRUCTOR =
85 new NativeProvider<NativeInfoMock>(NativeInfoMock.class, "native_info_mock") {};
Benjamin Petersonbf1db782018-08-08 10:03:22 -070086
Ulf Adams89f012d2015-02-26 13:39:28 +000087 @SkylarkModule(name = "Mock", doc = "")
Googlerab3cadc2019-11-08 15:17:21 -080088 class NativeInfoMock extends NativeInfo {
cparsons6c1c0662018-02-05 02:01:28 -080089
90 public NativeInfoMock() {
91 super(CONSTRUCTOR);
92 }
93
cparsons7f475d72018-03-30 13:54:46 -070094 @SkylarkCallable(name = "callable_string", documented = false, structField = false)
cparsons6c1c0662018-02-05 02:01:28 -080095 public String callableString() {
96 return "a";
97 }
98
cparsons7f475d72018-03-30 13:54:46 -070099 @SkylarkCallable(name = "struct_field_string", documented = false, structField = true)
cparsons6c1c0662018-02-05 02:01:28 -0800100 public String structFieldString() {
101 return "a";
102 }
103
cparsons7f475d72018-03-30 13:54:46 -0700104 @SkylarkCallable(name = "struct_field_callable", documented = false, structField = true)
Googlerab3cadc2019-11-08 15:17:21 -0800105 public BuiltinCallable structFieldCallable() {
adonovan4e2b4952019-12-10 12:19:20 -0800106 return new BuiltinCallable(SkylarkEvaluationTest.this, "foobar");
cparsons6c1c0662018-02-05 02:01:28 -0800107 }
108
109 @SkylarkCallable(
110 name = "struct_field_none",
cparsons7f475d72018-03-30 13:54:46 -0700111 documented = false,
cparsons6c1c0662018-02-05 02:01:28 -0800112 structField = true,
113 allowReturnNones = true
114 )
115 public String structFieldNone() {
116 return null;
117 }
118 }
119
120 @SkylarkModule(name = "Mock", doc = "")
Googler34f70582019-11-25 12:27:34 -0800121 class Mock implements StarlarkValue {
cparsons6c197202018-10-31 15:49:23 -0700122 @SkylarkCallable(
123 name = "MockFn",
124 selfCall = true,
125 documented = false,
cparsons0e866862018-04-24 08:07:02 -0700126 parameters = {
cparsons6c197202018-10-31 15:49:23 -0700127 @Param(name = "pos", positional = true, type = String.class),
128 })
129 public String selfCall(String myName) {
cparsons0e866862018-04-24 08:07:02 -0700130 return "I'm a mock named " + myName;
131 }
132
cparsons6c197202018-10-31 15:49:23 -0700133 @SkylarkCallable(
134 name = "value_of",
135 parameters = {@Param(name = "str", type = String.class)},
cparsonse661f882018-06-28 10:12:05 -0700136 documented = false)
cparsons6c197202018-10-31 15:49:23 -0700137 public Integer valueOf(String str) {
Ulf Adams89f012d2015-02-26 13:39:28 +0000138 return Integer.valueOf(str);
139 }
cparsonse661f882018-06-28 10:12:05 -0700140 @SkylarkCallable(name = "is_empty",
141 parameters = { @Param(name = "str", type = String.class) },
142 documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000143 public Boolean isEmpty(String str) {
144 return str.isEmpty();
145 }
146 public void value() {}
cparsons88d1cae2018-06-22 15:12:00 -0700147 @SkylarkCallable(name = "return_bad", documented = false)
Francois-Rene Rideau6c10eac2015-09-17 19:17:20 +0000148 public Bad returnBad() {
Googler084b64b2019-11-19 14:41:30 -0800149 return new Bad(); // not a legal Starlark value
Ulf Adams89f012d2015-02-26 13:39:28 +0000150 }
cparsons7f475d72018-03-30 13:54:46 -0700151 @SkylarkCallable(name = "struct_field", documented = false, structField = true)
Ulf Adams89f012d2015-02-26 13:39:28 +0000152 public String structField() {
153 return "a";
154 }
laurentlb6659b4c2019-02-18 07:23:36 -0800155
156 @SkylarkCallable(
157 name = "struct_field_with_extra",
cparsons07460fc2018-06-20 10:41:48 -0700158 documented = false,
159 structField = true,
laurentlb28c30a72019-06-13 07:52:42 -0700160 useStarlarkSemantics = true)
laurentlb6659b4c2019-02-18 07:23:36 -0800161 public String structFieldWithExtra(StarlarkSemantics sem) {
cparsons07460fc2018-06-20 10:41:48 -0700162 return "struct_field_with_extra("
163 + (sem != null)
164 + ")";
165 }
Googlerab3cadc2019-11-08 15:17:21 -0800166
cparsons7f475d72018-03-30 13:54:46 -0700167 @SkylarkCallable(name = "struct_field_callable", documented = false, structField = true)
Googlerab3cadc2019-11-08 15:17:21 -0800168 public Object structFieldCallable() {
adonovan4e2b4952019-12-10 12:19:20 -0800169 return new BuiltinCallable(SkylarkEvaluationTest.this, "foobar");
Vladimir Moskvaa5b16742016-10-31 14:09:41 +0000170 }
Benjamin Petersonbf1db782018-08-08 10:03:22 -0700171
172 @SkylarkCallable(name = "interrupted_struct_field", documented = false, structField = true)
173 public BuiltinFunction structFieldInterruptedCallable() throws InterruptedException {
174 throw new InterruptedException();
175 }
176
cparsons7f475d72018-03-30 13:54:46 -0700177 @SkylarkCallable(name = "function", documented = false, structField = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000178 public String function() {
179 return "a";
180 }
Googler34f70582019-11-25 12:27:34 -0800181
Ulf Adams89f012d2015-02-26 13:39:28 +0000182 @SuppressWarnings("unused")
Googler34f70582019-11-25 12:27:34 -0800183 @SkylarkCallable(
184 name = "nullfunc_failing",
cparsonse661f882018-06-28 10:12:05 -0700185 parameters = {
186 @Param(name = "p1", type = String.class),
187 @Param(name = "p2", type = Integer.class),
188 },
Googler34f70582019-11-25 12:27:34 -0800189 documented = false,
190 allowReturnNones = false)
191 public StarlarkValue nullfuncFailing(String p1, Integer p2) {
Ulf Adams89f012d2015-02-26 13:39:28 +0000192 return null;
193 }
Googler34f70582019-11-25 12:27:34 -0800194
cparsons7f475d72018-03-30 13:54:46 -0700195 @SkylarkCallable(name = "nullfunc_working", documented = false, allowReturnNones = true)
Googler34f70582019-11-25 12:27:34 -0800196 public StarlarkValue nullfuncWorking() {
Ulf Adams89f012d2015-02-26 13:39:28 +0000197 return null;
198 }
cparsons7f475d72018-03-30 13:54:46 -0700199 @SkylarkCallable(name = "voidfunc", documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000200 public void voidfunc() {}
cparsons7f475d72018-03-30 13:54:46 -0700201 @SkylarkCallable(name = "string_list", documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000202 public ImmutableList<String> stringList() {
203 return ImmutableList.<String>of("a", "b");
204 }
cparsons7f475d72018-03-30 13:54:46 -0700205 @SkylarkCallable(name = "string", documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000206 public String string() {
207 return "a";
208 }
cparsons7f475d72018-03-30 13:54:46 -0700209 @SkylarkCallable(name = "string_list_dict", documented = false)
cparsonsaaab11f2018-01-31 11:00:11 -0800210 public Map<String, List<String>> stringListDict() {
211 return ImmutableMap.of("a", ImmutableList.of("b", "c"));
212 }
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000213
cparsons4baafac2018-04-11 11:09:17 -0700214 @SkylarkCallable(
215 name = "legacy_method",
216 documented = false,
217 parameters = {
218 @Param(name = "pos", positional = true, type = Boolean.class),
219 @Param(name = "legacyNamed", type = Boolean.class, positional = true, named = false,
220 legacyNamed = true),
221 @Param(name = "named", type = Boolean.class, positional = false, named = true),
222 })
223 public String legacyMethod(Boolean pos, Boolean legacyNamed, Boolean named) {
224 return "legacy_method("
225 + pos
226 + ", "
227 + legacyNamed
228 + ", "
229 + named
230 + ")";
231 }
cparsons979195e2018-04-09 15:43:22 -0700232
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000233 @SkylarkCallable(
Googler4871cb02019-11-12 17:16:42 -0800234 name = "with_params",
235 documented = false,
236 parameters = {
237 @Param(name = "pos1"),
238 @Param(name = "pos2", defaultValue = "False", type = Boolean.class),
239 @Param(
240 name = "posOrNamed",
241 defaultValue = "False",
242 type = Boolean.class,
243 positional = true,
244 named = true),
245 @Param(name = "named", type = Boolean.class, positional = false, named = true),
246 @Param(
247 name = "optionalNamed",
248 type = Boolean.class,
249 defaultValue = "False",
250 positional = false,
251 named = true),
252 @Param(
253 name = "nonNoneable",
254 type = Object.class,
255 defaultValue = "\"a\"",
256 positional = false,
257 named = true),
258 @Param(
259 name = "noneable",
260 type = Integer.class,
261 defaultValue = "None",
262 noneable = true,
263 positional = false,
264 named = true),
265 @Param(
266 name = "multi",
267 allowedTypes = {
268 @ParamType(type = String.class),
269 @ParamType(type = Integer.class),
270 @ParamType(type = Sequence.class, generic1 = Integer.class),
271 },
272 defaultValue = "None",
273 noneable = true,
274 positional = false,
275 named = true)
276 })
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000277 public String withParams(
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +0000278 Integer pos1,
279 boolean pos2,
280 boolean posOrNamed,
281 boolean named,
282 boolean optionalNamed,
283 Object nonNoneable,
Dmitry Lomovd22e1de2017-09-25 08:53:50 -0400284 Object noneable,
285 Object multi) {
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000286 return "with_params("
287 + pos1
288 + ", "
289 + pos2
290 + ", "
291 + posOrNamed
292 + ", "
293 + named
294 + ", "
295 + optionalNamed
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +0000296 + ", "
cparsons5d446a72018-03-07 11:01:17 -0800297 + nonNoneable
Googler641bdf72019-11-12 10:32:26 -0800298 + (noneable != Starlark.NONE ? ", " + noneable : "")
299 + (multi != Starlark.NONE ? ", " + multi : "")
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000300 + ")";
301 }
302
cparsons5d446a72018-03-07 11:01:17 -0800303 @SkylarkCallable(
cparsonsb380dc92018-12-05 13:57:39 -0800304 name = "with_extra",
305 documented = false,
306 useLocation = true,
307 useAst = true,
Googlera3421e22019-09-26 06:48:32 -0700308 useStarlarkThread = true,
Googler7fa0dd22019-09-24 20:07:53 -0700309 useStarlarkSemantics = true)
cparsons5d446a72018-03-07 11:01:17 -0800310 public String withExtraInterpreterParams(
Googlera3421e22019-09-26 06:48:32 -0700311 Location location, FuncallExpression func, StarlarkThread thread, StarlarkSemantics sem) {
cparsons5d446a72018-03-07 11:01:17 -0800312 return "with_extra("
313 + location.getStartLine()
314 + ", "
315 + func.getArguments().size()
316 + ", "
Googlera3421e22019-09-26 06:48:32 -0700317 + thread.isGlobal()
cparsons73e10162018-03-22 10:02:02 -0700318 + ", "
319 + (sem != null)
cparsons5d446a72018-03-07 11:01:17 -0800320 + ")";
321 }
322
323 @SkylarkCallable(
laurentlb6659b4c2019-02-18 07:23:36 -0800324 name = "with_params_and_extra",
325 documented = false,
326 parameters = {
327 @Param(name = "pos1"),
328 @Param(name = "pos2", defaultValue = "False", type = Boolean.class),
329 @Param(
330 name = "posOrNamed",
331 defaultValue = "False",
332 type = Boolean.class,
333 positional = true,
334 named = true),
335 @Param(name = "named", type = Boolean.class, positional = false, named = true),
336 @Param(
337 name = "optionalNamed",
338 type = Boolean.class,
339 defaultValue = "False",
340 positional = false,
341 named = true),
342 @Param(
343 name = "nonNoneable",
344 type = Object.class,
345 defaultValue = "\"a\"",
346 positional = false,
347 named = true),
348 @Param(
349 name = "noneable",
350 type = Integer.class,
351 defaultValue = "None",
352 noneable = true,
353 positional = false,
354 named = true),
355 @Param(
356 name = "multi",
357 allowedTypes = {
358 @ParamType(type = String.class),
359 @ParamType(type = Integer.class),
Googler4871cb02019-11-12 17:16:42 -0800360 @ParamType(type = Sequence.class, generic1 = Integer.class),
laurentlb6659b4c2019-02-18 07:23:36 -0800361 },
362 defaultValue = "None",
363 noneable = true,
364 positional = false,
365 named = true)
366 },
367 useAst = true,
368 useLocation = true,
Googlera3421e22019-09-26 06:48:32 -0700369 useStarlarkThread = true,
laurentlb28c30a72019-06-13 07:52:42 -0700370 useStarlarkSemantics = true)
cparsons5d446a72018-03-07 11:01:17 -0800371 public String withParamsAndExtraInterpreterParams(
372 Integer pos1,
373 boolean pos2,
374 boolean posOrNamed,
375 boolean named,
376 boolean optionalNamed,
377 Object nonNoneable,
378 Object noneable,
379 Object multi,
380 Location location,
381 FuncallExpression func,
Googlera3421e22019-09-26 06:48:32 -0700382 StarlarkThread thread,
laurentlb6659b4c2019-02-18 07:23:36 -0800383 StarlarkSemantics sem) {
cparsons5d446a72018-03-07 11:01:17 -0800384 return "with_params_and_extra("
385 + pos1
386 + ", "
387 + pos2
388 + ", "
389 + posOrNamed
390 + ", "
391 + named
392 + ", "
393 + optionalNamed
394 + ", "
395 + nonNoneable
Googler641bdf72019-11-12 10:32:26 -0800396 + (noneable != Starlark.NONE ? ", " + noneable : "")
397 + (multi != Starlark.NONE ? ", " + multi : "")
cparsons5d446a72018-03-07 11:01:17 -0800398 + ", "
399 + location.getStartLine()
400 + ", "
401 + func.getArguments().size()
402 + ", "
Googlera3421e22019-09-26 06:48:32 -0700403 + thread.isGlobal()
cparsons73e10162018-03-22 10:02:02 -0700404 + ", "
405 + (sem != null)
cparsons5d446a72018-03-07 11:01:17 -0800406 + ")";
407 }
408
cparsons7520dcc2018-04-04 13:59:27 -0700409 @SkylarkCallable(name = "proxy_methods_object",
410 doc = "Returns a struct containing all callable method objects of this mock",
411 allowReturnNones = true)
412 public ClassObject proxyMethodsObject() {
413 ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
Googler2e63b2a2019-11-11 08:59:12 -0800414 Starlark.addMethods(builder, this);
cparsons0c5c1c62018-05-24 10:37:03 -0700415 return StructProvider.STRUCT.create(builder.build(), "no native callable '%s'");
cparsons7520dcc2018-04-04 13:59:27 -0700416 }
417
cparsons979195e2018-04-09 15:43:22 -0700418 @SkylarkCallable(
Googlera3421e22019-09-26 06:48:32 -0700419 name = "with_args_and_thread",
420 documented = false,
421 parameters = {
422 @Param(name = "pos1", type = Integer.class),
423 @Param(name = "pos2", defaultValue = "False", type = Boolean.class),
424 @Param(name = "named", type = Boolean.class, positional = false, named = true),
425 },
426 extraPositionals = @Param(name = "args"),
427 useStarlarkThread = true)
428 public String withArgsAndThread(
Googler4871cb02019-11-12 17:16:42 -0800429 Integer pos1, boolean pos2, boolean named, Sequence<?> args, StarlarkThread thread) {
Googler34f70582019-11-25 12:27:34 -0800430 String argsString = debugPrintArgs(args);
Googlera3421e22019-09-26 06:48:32 -0700431 return "with_args_and_thread("
cparsons979195e2018-04-09 15:43:22 -0700432 + pos1
433 + ", "
434 + pos2
435 + ", "
436 + named
437 + ", "
438 + argsString
439 + ", "
Googlera3421e22019-09-26 06:48:32 -0700440 + thread.isGlobal()
cparsons979195e2018-04-09 15:43:22 -0700441 + ")";
442 }
443
444 @SkylarkCallable(
Googlera9c93632019-11-13 10:48:07 -0800445 name = "with_kwargs",
446 documented = false,
447 parameters = {
448 @Param(name = "pos", defaultValue = "False", type = Boolean.class),
449 @Param(name = "named", type = Boolean.class, positional = false, named = true),
450 },
451 extraKeywords = @Param(name = "kwargs"))
452 public String withKwargs(boolean pos, boolean named, Dict<?, ?> kwargs) throws EvalException {
cparsons979195e2018-04-09 15:43:22 -0700453 String kwargsString =
454 "kwargs("
455 + kwargs
456 .getContents(String.class, Object.class, "kwargs")
457 .entrySet()
458 .stream()
459 .map(entry -> entry.getKey() + "=" + entry.getValue())
460 .collect(joining(", "))
461 + ")";
462 return "with_kwargs(" + pos + ", " + named + ", " + kwargsString + ")";
463 }
464
465 @SkylarkCallable(
Googler4871cb02019-11-12 17:16:42 -0800466 name = "with_args_and_kwargs",
467 documented = false,
468 parameters = {
469 @Param(name = "foo", named = true, positional = true, type = String.class),
470 },
471 extraPositionals = @Param(name = "args"),
472 extraKeywords = @Param(name = "kwargs"))
Googlera9c93632019-11-13 10:48:07 -0800473 public String withArgsAndKwargs(String foo, Sequence<?> args, Dict<?, ?> kwargs)
cparsons979195e2018-04-09 15:43:22 -0700474 throws EvalException {
Googler34f70582019-11-25 12:27:34 -0800475 String argsString = debugPrintArgs(args);
cparsons979195e2018-04-09 15:43:22 -0700476 String kwargsString =
477 "kwargs("
478 + kwargs
479 .getContents(String.class, Object.class, "kwargs")
480 .entrySet()
481 .stream()
482 .map(entry -> entry.getKey() + "=" + entry.getValue())
483 .collect(joining(", "))
484 + ")";
485 return "with_args_and_kwargs(" + foo + ", " + argsString + ", " + kwargsString + ")";
486 }
487
Benjamin Petersonaf53a112019-06-05 10:47:11 -0700488 @SkylarkCallable(name = "raise_unchecked_exception", documented = false)
489 public void raiseUncheckedException() {
490 throw new InternalError("buggy code");
491 }
492
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000493 @Override
494 public String toString() {
495 return "<mock>";
496 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000497 }
498
Googler34f70582019-11-25 12:27:34 -0800499 private static String debugPrintArgs(Iterable<?> args) {
500 Printer p = Printer.getPrinter();
501 p.append("args(");
502 String sep = "";
503 for (Object arg : args) {
504 p.append(sep).debugPrint(arg);
505 sep = ", ";
506 }
507 return p.append(")").toString();
508 }
509
Ulf Adams89f012d2015-02-26 13:39:28 +0000510 @SkylarkModule(name = "MockInterface", doc = "")
Googler34f70582019-11-25 12:27:34 -0800511 static interface MockInterface extends StarlarkValue {
cparsonse661f882018-06-28 10:12:05 -0700512 @SkylarkCallable(name = "is_empty_interface",
513 parameters = { @Param(name = "str", type = String.class) },
514 documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000515 public Boolean isEmptyInterface(String str);
516 }
517
cparsons4dc97ff2018-05-24 13:48:22 -0700518 @SkylarkModule(name = "MockSubClass", doc = "")
Googlerab3cadc2019-11-08 15:17:21 -0800519 final class MockSubClass extends Mock implements MockInterface {
Ulf Adams89f012d2015-02-26 13:39:28 +0000520 @Override
521 public Boolean isEmpty(String str) {
522 return str.isEmpty();
523 }
524 @Override
525 public Boolean isEmptyInterface(String str) {
526 return str.isEmpty();
527 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000528 }
529
cparsons7f475d72018-03-30 13:54:46 -0700530 @SkylarkModule(name = "MockClassObject", documented = false, doc = "")
Googler34f70582019-11-25 12:27:34 -0800531 static final class MockClassObject implements ClassObject, StarlarkValue {
Ulf Adams89f012d2015-02-26 13:39:28 +0000532 @Override
533 public Object getValue(String name) {
534 switch (name) {
535 case "field": return "a";
Googler084b64b2019-11-19 14:41:30 -0800536 case "nset":
537 return NestedSetBuilder.stableOrder().build(); // not a legal Starlark value
vladmos3ad44e32017-05-04 18:30:51 +0200538 default: return null;
Ulf Adams89f012d2015-02-26 13:39:28 +0000539 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000540 }
541
542 @Override
brandjond331fa72017-12-28 07:38:31 -0800543 public ImmutableCollection<String> getFieldNames() {
Ulf Adams89f012d2015-02-26 13:39:28 +0000544 return ImmutableList.of("field", "nset");
545 }
546
547 @Override
brandjond331fa72017-12-28 07:38:31 -0800548 public String getErrorMessageForUnknownField(String name) {
Ulf Adams89f012d2015-02-26 13:39:28 +0000549 return null;
550 }
551 }
552
cparsonsd3d05b22018-05-24 12:12:07 -0700553 @SkylarkModule(name = "ParamterizedMock", doc = "")
Googler34f70582019-11-25 12:27:34 -0800554 static interface ParameterizedApi<ObjectT> extends StarlarkValue {
cparsonsd3d05b22018-05-24 12:12:07 -0700555 @SkylarkCallable(
556 name = "method",
557 documented = false,
558 parameters = {
559 @Param(name = "foo", named = true, positional = true, type = Object.class),
560 }
561 )
562 public ObjectT method(ObjectT o);
563 }
564
565 static final class ParameterizedMock implements ParameterizedApi<String> {
566 @Override
567 public String method(String o) {
568 return o;
569 }
570 }
571
572 // Verifies that a method implementation overriding a parameterized annotated interface method
573 // is still treated as skylark-callable. Concretely, method() below should be treated as
574 // callable even though its method signature isn't an *exact* match of the annotated method
575 // declaration, due to the interface's method declaration being generic.
576 @Test
577 public void testParameterizedMock() throws Exception {
578 new SkylarkTest()
579 .update("mock", new ParameterizedMock())
580 .setUp("result = mock.method('bar')")
581 .testLookup("result", "bar");
Ulf Adams89f012d2015-02-26 13:39:28 +0000582 }
583
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000584 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000585 public void testSimpleIf() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000586 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000587 " a = 0",
588 " x = 0",
589 " if x: a = 5",
590 " return a",
Florian Weikert28da3652015-07-01 14:52:30 +0000591 "a = foo()").testLookup("a", 0);
Ulf Adams89f012d2015-02-26 13:39:28 +0000592 }
593
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000594 @Test
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000595 public void testIfPass() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000596 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000597 " a = 1",
598 " x = True",
599 " if x: pass",
600 " return a",
Florian Weikert28da3652015-07-01 14:52:30 +0000601 "a = foo()").testLookup("a", 1);
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000602 }
603
604 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000605 public void testNestedIf() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000606 executeNestedIf(0, 0, 0);
607 executeNestedIf(1, 0, 3);
608 executeNestedIf(1, 1, 5);
Ulf Adams89f012d2015-02-26 13:39:28 +0000609 }
610
Florian Weikert28da3652015-07-01 14:52:30 +0000611 private void executeNestedIf(int x, int y, int expected) throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000612 String fun = String.format("foo%s%s", x, y);
Florian Weikert28da3652015-07-01 14:52:30 +0000613 new SkylarkTest().setUp("def " + fun + "():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000614 " x = " + x,
615 " y = " + y,
616 " a = 0",
617 " b = 0",
618 " if x:",
619 " if y:",
620 " a = 2",
621 " b = 3",
622 " return a + b",
Florian Weikert28da3652015-07-01 14:52:30 +0000623 "x = " + fun + "()").testLookup("x", expected);
Ulf Adams89f012d2015-02-26 13:39:28 +0000624 }
625
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000626 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000627 public void testIfElse() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000628 executeIfElse("foo", "something", 2);
629 executeIfElse("bar", "", 3);
Ulf Adams89f012d2015-02-26 13:39:28 +0000630 }
631
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000632 private void executeIfElse(String fun, String y, int expected) throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000633 new SkylarkTest().setUp("def " + fun + "():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000634 " y = '" + y + "'",
635 " x = 5",
636 " if x:",
637 " if y: a = 2",
638 " else: a = 3",
Florian Weikert28da3652015-07-01 14:52:30 +0000639 " return a",
640 "z = " + fun + "()").testLookup("z", expected);
Ulf Adams89f012d2015-02-26 13:39:28 +0000641 }
642
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000643 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000644 public void testIfElifElse_IfExecutes() throws Exception {
645 execIfElifElse(1, 0, 1);
646 }
647
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000648 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000649 public void testIfElifElse_ElifExecutes() throws Exception {
650 execIfElifElse(0, 1, 2);
651 }
652
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000653 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000654 public void testIfElifElse_ElseExecutes() throws Exception {
655 execIfElifElse(0, 0, 3);
656 }
657
658 private void execIfElifElse(int x, int y, int v) throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000659 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000660 " x = " + x + "",
661 " y = " + y + "",
662 " if x:",
663 " return 1",
664 " elif y:",
665 " return 2",
666 " else:",
667 " return 3",
Florian Weikert28da3652015-07-01 14:52:30 +0000668 "v = foo()").testLookup("v", v);
Ulf Adams89f012d2015-02-26 13:39:28 +0000669 }
670
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000671 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000672 public void testForOnList() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000673 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000674 " s = ''",
675 " for i in ['hello', ' ', 'world']:",
676 " s = s + i",
677 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000678 "s = foo()").testLookup("s", "hello world");
Ulf Adams89f012d2015-02-26 13:39:28 +0000679 }
680
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000681 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000682 public void testForAssignmentList() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000683 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000684 " d = ['a', 'b', 'c']",
685 " s = ''",
686 " for i in d:",
687 " s = s + i",
Florian Weikert28da3652015-07-01 14:52:30 +0000688 " d = ['d', 'e', 'f']", // check that we use the old list
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000689 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000690 "s = foo()").testLookup("s", "abc");
Ulf Adams89f012d2015-02-26 13:39:28 +0000691 }
692
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000693 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000694 public void testForAssignmentDict() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000695 new SkylarkTest().setUp("def func():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000696 " d = {'a' : 1, 'b' : 2, 'c' : 3}",
697 " s = ''",
698 " for i in d:",
699 " s = s + i",
700 " d = {'d' : 1, 'e' : 2, 'f' : 3}",
701 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000702 "s = func()").testLookup("s", "abc");
Ulf Adams89f012d2015-02-26 13:39:28 +0000703 }
704
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000705 @Test
Jon Brandvein15775b22016-07-25 15:13:44 +0000706 public void testForUpdateList() throws Exception {
Jon Brandvein15775b22016-07-25 15:13:44 +0000707 new SkylarkTest().setUp("def foo():",
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000708 " xs = [1, 2, 3]",
Jon Brandvein15775b22016-07-25 15:13:44 +0000709 " for x in xs:",
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000710 " if x == 1:",
711 " xs.append(10)"
712 ).testIfErrorContains("trying to mutate a locked object", "foo()");
Jon Brandvein15775b22016-07-25 15:13:44 +0000713 }
714
715 @Test
716 public void testForUpdateDict() throws Exception {
Jon Brandvein15775b22016-07-25 15:13:44 +0000717 new SkylarkTest().setUp("def foo():",
718 " d = {'a': 1, 'b': 2, 'c': 3}",
Jon Brandvein15775b22016-07-25 15:13:44 +0000719 " for k in d:",
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000720 " d[k] *= 2"
721 ).testIfErrorContains("trying to mutate a locked object", "foo()");
722 }
723
724 @Test
725 public void testForUnlockedAfterBreak() throws Exception {
726 new SkylarkTest().setUp("def foo():",
727 " xs = [1, 2]",
728 " for x in xs:",
729 " break",
730 " xs.append(3)",
731 " return xs"
732 ).testEval("foo()", "[1, 2, 3]");
733 }
734
735 @Test
736 public void testForNestedOnSameListStillLocked() throws Exception {
737 new SkylarkTest().setUp("def foo():",
738 " xs = [1, 2]",
739 " ys = []",
740 " for x1 in xs:",
741 " for x2 in xs:",
742 " ys.append(x1 * x2)",
743 " xs.append(4)",
744 " return ys"
745 ).testIfErrorContains("trying to mutate a locked object", "foo()");
746 }
747
748 @Test
749 public void testForNestedOnSameListErrorMessage() throws Exception {
750 new SkylarkTest().setUp("def foo():",
751 " xs = [1, 2]",
752 " ys = []",
753 " for x1 in xs:",
754 " for x2 in xs:",
755 " ys.append(x1 * x2)",
756 " xs.append(4)",
757 " return ys"
758 // No file name in message, due to how test is set up.
Carmi Grushko46bf88c2017-02-20 22:37:15 +0000759 ).testIfErrorContains("Object locked at the following location(s): :4:3, :5:5", "foo()");
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000760 }
761
762 @Test
763 public void testForNestedOnSameListUnlockedAtEnd() 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 ).testEval("foo()", "[1, 2, 2, 4]");
773 }
774
775 @Test
776 public void testForNestedWithListCompGood() throws Exception {
777 new SkylarkTest().setUp("def foo():",
778 " xs = [1, 2]",
779 " ys = []",
780 " for x in xs:",
781 " zs = [None for x in xs for y in (ys.append(x) or ys)]",
782 " return ys"
783 ).testEval("foo()", "[1, 2, 1, 2]");
784 }
785 @Test
786 public void testForNestedWithListCompBad() throws Exception {
787 new SkylarkTest().setUp("def foo():",
788 " xs = [1, 2, 3]",
789 " ys = []",
790 " for x in xs:",
791 " zs = [None for x in xs for y in (xs.append(x) or ys)]",
792 " return ys"
793 ).testIfErrorContains("trying to mutate a locked object", "foo()");
Jon Brandvein15775b22016-07-25 15:13:44 +0000794 }
795
796 @Test
797 public void testForDeepUpdate() throws Exception {
798 // Check that indirectly reachable values can still be manipulated as normal.
Googler942e1c42019-11-12 13:11:44 -0800799 new SkylarkTest()
800 .setUp(
801 "def foo():",
802 " xs = [['a'], ['b'], ['c']]",
803 " ys = []",
804 " for x in xs:",
805 " for y in x:",
806 " ys.append(y)",
807 " xs[2].append(x[0])",
808 " return ys",
809 "ys = foo()")
810 .testLookup("ys", StarlarkList.of(null, "a", "b", "c", "a", "b"));
Jon Brandvein15775b22016-07-25 15:13:44 +0000811 }
812
813 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000814 public void testForNotIterable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000815 new SkylarkTest()
816 .update("mock", new Mock())
Florian Weikertc1d54ec2015-08-26 14:06:58 +0000817 .testIfErrorContains(
818 "type 'int' is not iterable",
819 "def func():",
820 " for i in mock.value_of('1'): a = i",
821 "func()\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000822 }
823
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000824 @Test
laurentlb26f843d2019-02-20 06:44:05 -0800825 public void testForStringNotIterable() throws Exception {
826 new SkylarkTest()
827 .update("mock", new Mock())
828 .testIfErrorContains(
829 "type 'string' is not iterable", "def func():", " for i in 'abc': a = i", "func()\n");
830 }
831
832 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000833 public void testForOnDictionary() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000834 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000835 " d = {1: 'a', 2: 'b', 3: 'c'}",
836 " s = ''",
837 " for i in d: s = s + d[i]",
838 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000839 "s = foo()").testLookup("s", "abc");
Ulf Adams89f012d2015-02-26 13:39:28 +0000840 }
841
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000842 @Test
Francois-Rene Rideau6c10eac2015-09-17 19:17:20 +0000843 public void testBadDictKey() throws Exception {
844 new SkylarkTest().testIfErrorContains(
845 "unhashable type: 'list'",
846 "{ [1, 2]: [3, 4] }");
847 }
848
849 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000850 public void testForLoopReuseVariable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000851 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000852 " s = ''",
853 " for i in ['a', 'b']:",
854 " for i in ['c', 'd']: s = s + i",
855 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000856 "s = foo()").testLookup("s", "cdcd");
Ulf Adams89f012d2015-02-26 13:39:28 +0000857 }
858
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000859 @Test
Laurent Le Brun741824b2015-03-20 15:10:19 +0000860 public void testForLoopMultipleVariables() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000861 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000862 " s = ''",
863 " for [i, j] in [[1, 2], [3, 4]]:",
864 " s = s + str(i) + str(j) + '.'",
865 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000866 "s = foo()").testLookup("s", "12.34.");
Laurent Le Brun741824b2015-03-20 15:10:19 +0000867 }
868
869 @Test
Florian Weikert917ceaa2015-06-10 13:54:26 +0000870 public void testForLoopBreak() throws Exception {
871 simpleFlowTest("break", 1);
872 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000873
Florian Weikert917ceaa2015-06-10 13:54:26 +0000874 @Test
875 public void testForLoopContinue() throws Exception {
876 simpleFlowTest("continue", 10);
877 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000878
Florian Weikert917ceaa2015-06-10 13:54:26 +0000879 @SuppressWarnings("unchecked")
880 private void simpleFlowTest(String statement, int expected) throws Exception {
Googler1a1fca22019-10-14 09:31:22 -0700881 exec(
882 "def foo():",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000883 " s = 0",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000884 " hit = 0",
885 " for i in range(0, 10):",
886 " s = s + 1",
887 " " + statement + "",
888 " hit = 1",
889 " return [s, hit]",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000890 "x = foo()");
891 assertThat((Iterable<Object>) lookup("x")).containsExactly(expected, 0).inOrder();
892 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000893
894 @Test
Florian Weikert917ceaa2015-06-10 13:54:26 +0000895 public void testForLoopBreakFromDeeperBlock() throws Exception {
896 flowFromDeeperBlock("break", 1);
897 flowFromNestedBlocks("break", 29);
898 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000899
900 @Test
Florian Weikert917ceaa2015-06-10 13:54:26 +0000901 public void testForLoopContinueFromDeeperBlock() throws Exception {
902 flowFromDeeperBlock("continue", 5);
903 flowFromNestedBlocks("continue", 39);
904 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000905
Florian Weikert917ceaa2015-06-10 13:54:26 +0000906 private void flowFromDeeperBlock(String statement, int expected) throws Exception {
Googler1a1fca22019-10-14 09:31:22 -0700907 exec(
908 "def foo():",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000909 " s = 0",
910 " for i in range(0, 10):",
911 " if i % 2 != 0:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000912 " " + statement + "",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000913 " s = s + 1",
914 " return s",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000915 "x = foo()");
916 assertThat(lookup("x")).isEqualTo(expected);
917 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000918
Florian Weikert917ceaa2015-06-10 13:54:26 +0000919 private void flowFromNestedBlocks(String statement, int expected) throws Exception {
Googler1a1fca22019-10-14 09:31:22 -0700920 exec(
921 "def foo2():",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000922 " s = 0",
923 " for i in range(1, 41):",
924 " if i % 2 == 0:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000925 " if i % 3 == 0:",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000926 " if i % 5 == 0:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000927 " " + statement + "",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000928 " s = s + 1",
929 " return s",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000930 "y = foo2()");
931 assertThat(lookup("y")).isEqualTo(expected);
932 }
933
934 @Test
935 public void testNestedForLoopsMultipleBreaks() throws Exception {
936 nestedLoopsTest("break", 2, 6, 6);
937 }
938
939 @Test
940 public void testNestedForLoopsMultipleContinues() throws Exception {
941 nestedLoopsTest("continue", 4, 20, 20);
942 }
943
944 @SuppressWarnings("unchecked")
945 private void nestedLoopsTest(String statement, Integer outerExpected, int firstExpected,
946 int secondExpected) throws Exception {
Googler1a1fca22019-10-14 09:31:22 -0700947 exec(
948 "def foo():",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000949 " outer = 0",
950 " first = 0",
951 " second = 0",
952 " for i in range(0, 5):",
953 " for j in range(0, 5):",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000954 " if j == 2:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000955 " " + statement + "",
956 " first = first + 1",
957 " for k in range(0, 5):",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000958 " if k == 2:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000959 " " + statement + "",
960 " second = second + 1",
961 " if i == 2:",
962 " " + statement + "",
963 " outer = outer + 1",
964 " return [outer, first, second]",
965 "x = foo()");
966 assertThat((Iterable<Object>) lookup("x"))
967 .containsExactly(outerExpected, firstExpected, secondExpected).inOrder();
968 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000969
Florian Weikert917ceaa2015-06-10 13:54:26 +0000970 @Test
971 public void testForLoopBreakError() throws Exception {
972 flowStatementInsideFunction("break");
973 flowStatementAfterLoop("break");
974 }
975
976 @Test
977 public void testForLoopContinueError() throws Exception {
978 flowStatementInsideFunction("continue");
979 flowStatementAfterLoop("continue");
980 }
981
Googlerf0890f02019-10-01 07:28:48 -0700982 // TODO(adonovan): move this and all tests that use it to Validation tests.
983 private void assertValidationError(String expectedError, final String... lines) throws Exception {
Googler1a1fca22019-10-14 09:31:22 -0700984 SyntaxError error = assertThrows(SyntaxError.class, () -> exec(lines));
Googlerf0890f02019-10-01 07:28:48 -0700985 assertThat(error).hasMessageThat().contains(expectedError);
986 }
987
Florian Weikert917ceaa2015-06-10 13:54:26 +0000988 private void flowStatementInsideFunction(String statement) throws Exception {
Googlerf0890f02019-10-01 07:28:48 -0700989 assertValidationError(
990 statement + " statement must be inside a for loop",
991 //
Florian Weikert917ceaa2015-06-10 13:54:26 +0000992 "def foo():",
brandjone5d95fb2017-07-13 17:23:09 +0200993 " " + statement,
Florian Weikert917ceaa2015-06-10 13:54:26 +0000994 "x = foo()");
995 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000996
Googlerf0890f02019-10-01 07:28:48 -0700997 private void flowStatementAfterLoop(String statement) throws Exception {
998 assertValidationError(
999 statement + " statement must be inside a for loop",
1000 //
Florian Weikert917ceaa2015-06-10 13:54:26 +00001001 "def foo2():",
1002 " for i in range(0, 3):",
1003 " pass",
brandjone5d95fb2017-07-13 17:23:09 +02001004 " " + statement,
Florian Weikert917ceaa2015-06-10 13:54:26 +00001005 "y = foo2()");
1006 }
Florian Weikert28da3652015-07-01 14:52:30 +00001007
Florian Weikert917ceaa2015-06-10 13:54:26 +00001008 @Test
Googlerf0890f02019-10-01 07:28:48 -07001009 public void testStructMembersAreImmutable() throws Exception {
1010 assertValidationError("cannot assign to 's.x'", "s = struct(x = 'a')", "s.x = 'b'\n");
1011 }
1012
1013 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001014 public void testNoneAssignment() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001015 new SkylarkTest()
1016 .setUp("def foo(x=None):", " x = 1", " x = None", " return 2", "s = foo()")
1017 .testLookup("s", 2);
Ulf Adams89f012d2015-02-26 13:39:28 +00001018 }
1019
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001020 @Test
Laurent Le Brun88014fe2015-06-17 16:02:16 +00001021 public void testReassignment() throws Exception {
Googler1a1fca22019-10-14 09:31:22 -07001022 exec(
1023 "def foo(x=None):", //
Laurent Le Brun88014fe2015-06-17 16:02:16 +00001024 " x = 1",
1025 " x = [1, 2]",
1026 " x = 'str'",
1027 " return x",
1028 "s = foo()");
1029 assertThat(lookup("s")).isEqualTo("str");
1030 }
1031
1032 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001033 public void testJavaCalls() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001034 new SkylarkTest()
1035 .update("mock", new Mock())
1036 .setUp("b = mock.is_empty('a')")
1037 .testLookup("b", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001038 }
1039
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001040 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001041 public void testJavaCallsOnSubClass() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001042 new SkylarkTest()
1043 .update("mock", new MockSubClass())
1044 .setUp("b = mock.is_empty('a')")
1045 .testLookup("b", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001046 }
1047
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001048 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001049 public void testJavaCallsOnInterface() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001050 new SkylarkTest()
1051 .update("mock", new MockSubClass())
1052 .setUp("b = mock.is_empty_interface('a')")
1053 .testLookup("b", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001054 }
1055
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001056 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001057 public void testJavaCallsNotSkylarkCallable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001058 new SkylarkTest()
1059 .update("mock", new Mock())
adonovan4e2b4952019-12-10 12:19:20 -08001060 .testIfExactError("'Mock' value has no field or method 'value'", "mock.value()");
Laurent Le Brun648f8f32015-09-09 19:46:29 +00001061 }
1062
1063 @Test
1064 public void testNoOperatorIndex() throws Exception {
1065 new SkylarkTest()
1066 .update("mock", new Mock())
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001067 .testIfExactError("type 'Mock' has no operator [](int)", "mock[2]");
Ulf Adams89f012d2015-02-26 13:39:28 +00001068 }
1069
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001070 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001071 public void testJavaCallsNoMethod() throws Exception {
Francois-Rene Rideau676905a2015-08-31 15:39:09 +00001072 new SkylarkTest()
1073 .update("mock", new Mock())
adonovan4e2b4952019-12-10 12:19:20 -08001074 .testIfExactError("'Mock' value has no field or method 'bad'", "mock.bad()");
Ulf Adams89f012d2015-02-26 13:39:28 +00001075 }
1076
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001077 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001078 public void testJavaCallsNoMethodErrorMsg() throws Exception {
Laurent Le Brun648f8f32015-09-09 19:46:29 +00001079 new SkylarkTest()
adonovan4e2b4952019-12-10 12:19:20 -08001080 .testIfExactError("'int' value has no field or method 'bad'", "s = 3.bad('a', 'b', 'c')");
Ulf Adams89f012d2015-02-26 13:39:28 +00001081 }
1082
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001083 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001084 public void testJavaCallWithKwargs() throws Exception {
Francois-Rene Rideau676905a2015-08-31 15:39:09 +00001085 new SkylarkTest()
1086 .update("mock", new Mock())
adonovan4e2b4952019-12-10 12:19:20 -08001087 .testIfExactError(
1088 "'Mock' value has no field or method 'isEmpty'", "mock.isEmpty(str='abc')");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001089 }
1090
cparsonsaaab11f2018-01-31 11:00:11 -08001091 @Test
1092 public void testStringListDictValues() throws Exception {
1093 new SkylarkTest()
1094 .update("mock", new Mock())
1095 .setUp(
1096 "def func(mock):",
1097 " for i, v in mock.string_list_dict().items():",
1098 " modified_list = v + ['extra_string']",
1099 " return modified_list",
1100 "m = func(mock)")
Googler92578702019-11-21 12:19:31 -08001101 .testLookup("m", StarlarkList.of(thread.mutability(), "b", "c", "extra_string"));
cparsonsaaab11f2018-01-31 11:00:11 -08001102 }
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001103
1104 @Test
cparsons7520dcc2018-04-04 13:59:27 -07001105 public void testProxyMethodsObject() throws Exception {
1106 new SkylarkTest()
1107 .update("mock", new Mock())
1108 .setUp(
1109 "m = mock.proxy_methods_object()",
1110 "b = m.with_params(1, True, named=True)")
1111 .testLookup("b", "with_params(1, true, false, true, false, a)");
1112 }
1113
cparsons4baafac2018-04-11 11:09:17 -07001114 @Test
1115 public void testLegacyNamed() throws Exception {
cparsons65ecfea2019-08-28 14:37:23 -07001116 new SkylarkTest("--incompatible_restrict_named_params=false")
cparsons4baafac2018-04-11 11:09:17 -07001117 .update("mock", new Mock())
cparsons65ecfea2019-08-28 14:37:23 -07001118 .setUp("b = mock.legacy_method(True, legacyNamed=True, named=True)")
cparsons4baafac2018-04-11 11:09:17 -07001119 .testLookup("b", "legacy_method(true, true, true)");
1120
cparsons65ecfea2019-08-28 14:37:23 -07001121 new SkylarkTest("--incompatible_restrict_named_params=false")
cparsons4baafac2018-04-11 11:09:17 -07001122 .update("mock", new Mock())
cparsons65ecfea2019-08-28 14:37:23 -07001123 .setUp("b = mock.legacy_method(True, True, named=True)")
cparsons4baafac2018-04-11 11:09:17 -07001124 .testLookup("b", "legacy_method(true, true, true)");
1125
1126 // Verify legacyNamed also works with proxy method objects.
cparsons65ecfea2019-08-28 14:37:23 -07001127 new SkylarkTest("--incompatible_restrict_named_params=false")
cparsons4baafac2018-04-11 11:09:17 -07001128 .update("mock", new Mock())
1129 .setUp(
1130 "m = mock.proxy_methods_object()",
1131 "b = m.legacy_method(True, legacyNamed=True, named=True)")
1132 .testLookup("b", "legacy_method(true, true, true)");
1133
cparsons65ecfea2019-08-28 14:37:23 -07001134 new SkylarkTest("--incompatible_restrict_named_params=false")
cparsons4baafac2018-04-11 11:09:17 -07001135 .update("mock", new Mock())
cparsons65ecfea2019-08-28 14:37:23 -07001136 .setUp("m = mock.proxy_methods_object()", "b = m.legacy_method(True, True, named=True)")
cparsons4baafac2018-04-11 11:09:17 -07001137 .testLookup("b", "legacy_method(true, true, true)");
1138 }
1139
cparsons74f78972018-04-06 12:55:47 -07001140 /**
1141 * This test verifies an error is raised when a method parameter is set both positionally and
1142 * by name.
1143 */
1144 @Test
1145 public void testArgSpecifiedBothByNameAndPosition() throws Exception {
1146 // in with_params, 'posOrNamed' is positional parameter index 2. So by specifying both
1147 // posOrNamed by name and three positional parameters, there is a conflict.
1148 new SkylarkTest()
1149 .update("mock", new Mock())
1150 .testIfErrorContains("got multiple values for keyword argument 'posOrNamed'",
1151 "mock.with_params(1, True, True, posOrNamed=True, named=True)");
1152 }
1153
1154 @Test
1155 public void testTooManyPositionalArgs() throws Exception {
1156 new SkylarkTest()
1157 .update("mock", new Mock())
1158 .testIfErrorContains("expected no more than 3 positional arguments, but got 4",
1159 "mock.with_params(1, True, True, 'toomany', named=True)");
1160
1161 new SkylarkTest()
1162 .update("mock", new Mock())
1163 .testIfErrorContains("expected no more than 3 positional arguments, but got 5",
1164 "mock.with_params(1, True, True, 'toomany', 'alsotoomany', named=True)");
1165
1166 new SkylarkTest()
1167 .update("mock", new Mock())
1168 .testIfErrorContains("expected no more than 1 positional arguments, but got 2",
1169 "mock.is_empty('a', 'b')");
1170 }
1171
cparsons7520dcc2018-04-04 13:59:27 -07001172 @Test
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001173 public void testJavaCallWithPositionalAndKwargs() throws Exception {
1174 new SkylarkTest()
1175 .update("mock", new Mock())
1176 .setUp("b = mock.with_params(1, True, named=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001177 .testLookup("b", "with_params(1, true, false, true, false, a)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001178 new SkylarkTest()
1179 .update("mock", new Mock())
Dmitry Lomovd22e1de2017-09-25 08:53:50 -04001180 .setUp("b = mock.with_params(1, True, named=True, multi=1)")
1181 .testLookup("b", "with_params(1, true, false, true, false, a, 1)");
1182 new SkylarkTest()
1183 .update("mock", new Mock())
1184 .setUp("b = mock.with_params(1, True, named=True, multi='abc')")
1185 .testLookup("b", "with_params(1, true, false, true, false, a, abc)");
1186
1187 new SkylarkTest()
1188 .update("mock", new Mock())
1189 .setUp("b = mock.with_params(1, True, named=True, multi=[1,2,3])")
1190 .testLookup("b", "with_params(1, true, false, true, false, a, [1, 2, 3])");
1191
1192 new SkylarkTest()
1193 .update("mock", new Mock())
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001194 .setUp("")
1195 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001196 "parameter 'named' has no default value, for call to "
1197 + "method with_params(pos1, pos2 = False, posOrNamed = False, named, "
1198 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1199 + "of 'Mock'",
Pedro Liberal Fernandez92f06a52016-09-28 07:33:42 +00001200 "mock.with_params(1, True)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001201 new SkylarkTest()
1202 .update("mock", new Mock())
1203 .setUp("")
1204 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001205 "parameter 'named' has no default value, for call to "
1206 + "method with_params(pos1, pos2 = False, posOrNamed = False, named, "
1207 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001208 + "of 'Mock'",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001209 "mock.with_params(1, True, True)");
1210 new SkylarkTest()
1211 .update("mock", new Mock())
1212 .setUp("b = mock.with_params(1, True, True, named=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001213 .testLookup("b", "with_params(1, true, true, true, false, a)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001214 new SkylarkTest()
1215 .update("mock", new Mock())
1216 .setUp("b = mock.with_params(1, True, named=True, posOrNamed=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001217 .testLookup("b", "with_params(1, true, true, true, false, a)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001218 new SkylarkTest()
1219 .update("mock", new Mock())
1220 .setUp("b = mock.with_params(1, True, named=True, posOrNamed=True, optionalNamed=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001221 .testLookup("b", "with_params(1, true, true, true, true, a)");
Pedro Liberal Fernandez837dbc12016-08-18 14:13:01 +00001222 new SkylarkTest()
1223 .update("mock", new Mock())
1224 .setUp("")
1225 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001226 "unexpected keyword 'n', for call to "
1227 + "method with_params(pos1, pos2 = False, posOrNamed = False, named, "
1228 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1229 + "of 'Mock'",
Pedro Liberal Fernandez837dbc12016-08-18 14:13:01 +00001230 "mock.with_params(1, True, named=True, posOrNamed=True, n=2)");
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001231 new SkylarkTest()
1232 .update("mock", new Mock())
1233 .setUp("")
1234 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001235 "parameter 'nonNoneable' cannot be None, for call to method "
1236 + "with_params(pos1, pos2 = False, posOrNamed = False, named, "
1237 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1238 + "of 'Mock'",
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001239 "mock.with_params(1, True, True, named=True, optionalNamed=False, nonNoneable=None)");
Dmitry Lomovd22e1de2017-09-25 08:53:50 -04001240
1241 new SkylarkTest()
1242 .update("mock", new Mock())
1243 .setUp("")
1244 .testIfExactError(
cparsonsa95884e2018-03-21 11:06:13 -07001245 "expected value of type 'string or int or sequence of ints or NoneType' for parameter"
cparsons03035142019-01-15 13:35:22 -08001246 + " 'multi', for call to method "
1247 + "with_params(pos1, pos2 = False, posOrNamed = False, named, "
1248 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1249 + "of 'Mock'",
Dmitry Lomovd22e1de2017-09-25 08:53:50 -04001250 "mock.with_params(1, True, named=True, multi=False)");
1251
1252 // We do not enforce list item parameter type constraints.
1253 // Test for this behavior.
1254 new SkylarkTest()
1255 .update("mock", new Mock())
1256 .setUp("b = mock.with_params(1, True, named=True, multi=['a', 'b'])")
1257 .testLookup("b", "with_params(1, true, false, true, false, a, [\"a\", \"b\"])");
Ulf Adams89f012d2015-02-26 13:39:28 +00001258 }
1259
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001260 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001261 public void testNoJavaCallsWithoutSkylark() throws Exception {
adonovan4e2b4952019-12-10 12:19:20 -08001262 new SkylarkTest()
1263 .testIfExactError("'int' value has no field or method 'to_string'", "s = 3.to_string()");
Laurent Le Brun648f8f32015-09-09 19:46:29 +00001264 }
Ulf Adams89f012d2015-02-26 13:39:28 +00001265
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001266 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001267 public void testStructAccess() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001268 new SkylarkTest()
1269 .update("mock", new Mock())
1270 .setUp("v = mock.struct_field")
1271 .testLookup("v", "a");
Ulf Adams89f012d2015-02-26 13:39:28 +00001272 }
1273
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001274 @Test
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001275 public void testStructAccessAsFuncallNonCallable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001276 new SkylarkTest()
1277 .update("mock", new Mock())
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001278 .testIfExactError("'string' object is not callable", "v = mock.struct_field()");
1279 }
1280
1281 @Test
cparsons0e866862018-04-24 08:07:02 -07001282 public void testSelfCall() throws Exception {
1283 new SkylarkTest()
1284 .update("mock", new Mock())
1285 .setUp("v = mock('bestmock')")
1286 .testLookup("v", "I'm a mock named bestmock");
1287
1288 new SkylarkTest()
1289 .update("mock", new Mock())
1290 .setUp("mockfunction = mock", "v = mockfunction('bestmock')")
1291 .testLookup("v", "I'm a mock named bestmock");
1292
1293 new SkylarkTest()
1294 .update("mock", new Mock())
1295 .testIfErrorContains(
cparsons03035142019-01-15 13:35:22 -08001296 "expected value of type 'string' for parameter 'pos', for call to function MockFn(pos)",
cparsons0e866862018-04-24 08:07:02 -07001297 "v = mock(1)");
1298 }
1299
1300 @Test
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001301 public void testStructAccessAsFuncall() throws Exception {
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001302 new SkylarkTest()
1303 .update("mock", new Mock())
1304 .setUp("v = mock.struct_field_callable()")
1305 .testLookup("v", "foobar");
Ulf Adams89f012d2015-02-26 13:39:28 +00001306 }
1307
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001308 @Test
Benjamin Petersonbf1db782018-08-08 10:03:22 -07001309 public void testCallingInterruptedStructField() throws Exception {
1310 update("mock", new Mock());
1311 assertThrows(InterruptedException.class, () -> eval("mock.interrupted_struct_field()"));
1312 }
1313
1314 @Test
1315 public void testCallingInterruptedFunction() throws Exception {
adonovan4e2b4952019-12-10 12:19:20 -08001316 update("interrupted_function", new BuiltinCallable(this, "interrupted_function"));
Benjamin Petersonbf1db782018-08-08 10:03:22 -07001317 assertThrows(InterruptedException.class, () -> eval("interrupted_function()"));
1318 }
1319
1320 @Test
Benjamin Petersonaf53a112019-06-05 10:47:11 -07001321 public void testCallingMethodThatRaisesUncheckedException() throws Exception {
1322 update("mock", new Mock());
1323 assertThrows(InternalError.class, () -> eval("mock.raise_unchecked_exception()"));
1324 }
1325
1326 @Test
cparsons5d446a72018-03-07 11:01:17 -08001327 public void testJavaFunctionWithExtraInterpreterParams() throws Exception {
1328 new SkylarkTest()
1329 .update("mock", new Mock())
1330 .setUp("v = mock.with_extra()")
Googler7fa0dd22019-09-24 20:07:53 -07001331 .testLookup("v", "with_extra(1, 0, true, true)");
cparsons5d446a72018-03-07 11:01:17 -08001332 }
1333
1334 @Test
cparsons07460fc2018-06-20 10:41:48 -07001335 public void testStructFieldWithExtraInterpreterParams() throws Exception {
1336 new SkylarkTest()
1337 .update("mock", new Mock())
1338 .setUp("v = mock.struct_field_with_extra")
1339 .testLookup("v", "struct_field_with_extra(true)");
1340 }
1341
1342 @Test
cparsons5d446a72018-03-07 11:01:17 -08001343 public void testJavaFunctionWithParamsAndExtraInterpreterParams() throws Exception {
1344 new SkylarkTest()
1345 .update("mock", new Mock())
1346 .setUp("b = mock.with_params_and_extra(1, True, named=True)")
cparsons73e10162018-03-22 10:02:02 -07001347 .testLookup("b", "with_params_and_extra(1, true, false, true, false, a, 1, 3, true, true)");
cparsons5d446a72018-03-07 11:01:17 -08001348 }
1349
1350 @Test
Googlera3421e22019-09-26 06:48:32 -07001351 public void testJavaFunctionWithExtraArgsAndThread() throws Exception {
cparsons979195e2018-04-09 15:43:22 -07001352 new SkylarkTest()
1353 .update("mock", new Mock())
Googlera3421e22019-09-26 06:48:32 -07001354 .setUp("b = mock.with_args_and_thread(1, True, 'extraArg1', 'extraArg2', named=True)")
1355 .testLookup("b", "with_args_and_thread(1, true, true, args(extraArg1, extraArg2), true)");
cparsons979195e2018-04-09 15:43:22 -07001356
1357 // Use an args list.
1358 new SkylarkTest()
1359 .update("mock", new Mock())
1360 .setUp(
1361 "myargs = ['extraArg2']",
Googlera3421e22019-09-26 06:48:32 -07001362 "b = mock.with_args_and_thread(1, True, 'extraArg1', named=True, *myargs)")
1363 .testLookup("b", "with_args_and_thread(1, true, true, args(extraArg1, extraArg2), true)");
cparsons979195e2018-04-09 15:43:22 -07001364 }
1365
1366 @Test
1367 public void testJavaFunctionWithExtraKwargs() throws Exception {
1368 new SkylarkTest()
1369 .update("mock", new Mock())
1370 .setUp("b = mock.with_kwargs(True, extraKey1=True, named=True, extraKey2='x')")
1371 .testLookup("b", "with_kwargs(true, true, kwargs(extraKey1=true, extraKey2=x))");
1372
1373 // Use a kwargs dict.
1374 new SkylarkTest()
1375 .update("mock", new Mock())
1376 .setUp(
1377 "mykwargs = {'extraKey2':'x', 'named':True}",
1378 "b = mock.with_kwargs(True, extraKey1=True, **mykwargs)")
1379 .testLookup("b", "with_kwargs(true, true, kwargs(extraKey1=true, extraKey2=x))");
1380 }
1381
1382 @Test
1383 public void testJavaFunctionWithArgsAndKwargs() throws Exception {
1384 // Foo is used positionally
1385 new SkylarkTest()
1386 .update("mock", new Mock())
1387 .setUp("b = mock.with_args_and_kwargs('foo', 'bar', 'baz', extraKey1=True, extraKey2='x')")
1388 .testLookup(
1389 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey1=true, extraKey2=x))");
1390
1391 // Use an args list and a kwargs dict
1392 new SkylarkTest()
1393 .update("mock", new Mock())
1394 .setUp(
1395 "mykwargs = {'extraKey1':True}",
1396 "myargs = ['baz']",
1397 "b = mock.with_args_and_kwargs('foo', 'bar', extraKey2='x', *myargs, **mykwargs)")
1398 .testLookup(
1399 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey2=x, extraKey1=true))");
1400
1401 // Foo is used by name
1402 new SkylarkTest()
1403 .update("mock", new Mock())
1404 .setUp("b = mock.with_args_and_kwargs(foo='foo', extraKey1=True)")
1405 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs(extraKey1=true))");
1406
1407 // Empty args and kwargs.
1408 new SkylarkTest()
1409 .update("mock", new Mock())
1410 .setUp("b = mock.with_args_and_kwargs('foo')")
1411 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs())");
1412 }
1413
1414 @Test
1415 public void testProxyMethodsObjectWithArgsAndKwargs() throws Exception {
1416 // Foo is used positionally
1417 new SkylarkTest()
1418 .update("mock", new Mock())
1419 .setUp(
1420 "m = mock.proxy_methods_object()",
1421 "b = m.with_args_and_kwargs('foo', 'bar', 'baz', extraKey1=True, extraKey2='x')")
1422 .testLookup(
1423 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey1=true, extraKey2=x))");
1424
1425 // Use an args list and a kwargs dict
1426 new SkylarkTest()
1427 .update("mock", new Mock())
1428 .setUp(
1429 "mykwargs = {'extraKey1':True}",
1430 "myargs = ['baz']",
1431 "m = mock.proxy_methods_object()",
1432 "b = m.with_args_and_kwargs('foo', 'bar', extraKey2='x', *myargs, **mykwargs)")
1433 .testLookup(
1434 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey2=x, extraKey1=true))");
1435
1436 // Foo is used by name
1437 new SkylarkTest()
1438 .update("mock", new Mock())
1439 .setUp(
1440 "m = mock.proxy_methods_object()",
1441 "b = m.with_args_and_kwargs(foo='foo', extraKey1=True)")
1442 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs(extraKey1=true))");
1443
1444 // Empty args and kwargs.
1445 new SkylarkTest()
1446 .update("mock", new Mock())
1447 .setUp("m = mock.proxy_methods_object()", "b = m.with_args_and_kwargs('foo')")
1448 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs())");
1449 }
1450
1451 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001452 public void testStructAccessOfMethod() throws Exception {
Googler1a1fca22019-10-14 09:31:22 -07001453 new SkylarkTest().update("mock", new Mock()).testExpression("type(mock.function)", "function");
1454 new SkylarkTest().update("mock", new Mock()).testExpression("mock.function()", "a");
Laurent Le Brun57badf42017-01-02 15:12:24 +00001455 }
1456
1457 @Test
1458 public void testStructAccessTypo() throws Exception {
1459 new SkylarkTest()
1460 .update("mock", new MockClassObject())
1461 .testIfExactError(
adonovan4e2b4952019-12-10 12:19:20 -08001462 "'MockClassObject' value has no field or method 'fild' (did you mean 'field'?)",
Laurent Le Brun57badf42017-01-02 15:12:24 +00001463 "mock.fild");
Ulf Adams89f012d2015-02-26 13:39:28 +00001464 }
1465
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001466 @Test
Googler055d6c62018-05-22 13:21:04 -07001467 public void testStructAccessType_nonClassObject() throws Exception {
1468 new SkylarkTest()
1469 .update("mock", new Mock())
1470 .testIfExactError(
adonovan4e2b4952019-12-10 12:19:20 -08001471 "'Mock' value has no field or method 'sturct_field' (did you mean 'struct_field'?)",
Googler055d6c62018-05-22 13:21:04 -07001472 "v = mock.sturct_field");
1473 }
1474
1475 @Test
Googler084b64b2019-11-19 14:41:30 -08001476 public void testJavaFunctionReturnsIllegalValue() throws Exception {
1477 update("mock", new Mock());
1478 IllegalArgumentException e =
1479 assertThrows(IllegalArgumentException.class, () -> eval("mock.return_bad()"));
1480 assertThat(e)
1481 .hasMessageThat()
1482 .contains(
1483 "cannot expose internal type to Starlark: class"
1484 + " com.google.devtools.build.lib.syntax.SkylarkEvaluationTest$Bad");
Ulf Adams89f012d2015-02-26 13:39:28 +00001485 }
1486
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001487 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001488 public void testJavaFunctionReturnsNullFails() throws Exception {
Benjamin Petersonaf53a112019-06-05 10:47:11 -07001489 update("mock", new Mock());
1490 IllegalStateException e =
1491 assertThrows(IllegalStateException.class, () -> eval("mock.nullfunc_failing('abc', 1)"));
1492 assertThat(e).hasMessageThat().contains("method invocation returned None");
Ulf Adams89f012d2015-02-26 13:39:28 +00001493 }
1494
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001495 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001496 public void testClassObjectAccess() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001497 new SkylarkTest()
1498 .update("mock", new MockClassObject())
1499 .setUp("v = mock.field")
1500 .testLookup("v", "a");
Ulf Adams89f012d2015-02-26 13:39:28 +00001501 }
1502
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001503 @Test
Laurent Le Brun092f13b2015-08-24 14:50:00 +00001504 public void testUnionSet() throws Exception {
laurentlb63c7ea62019-04-25 08:45:21 -07001505 new SkylarkTest("--incompatible_depset_union=false")
Googler1a1fca22019-10-14 09:31:22 -07001506 .testExpression("str(depset([1, 3]) | depset([1, 2]))", "depset([1, 2, 3])")
1507 .testExpression("str(depset([1, 2]) | [1, 3])", "depset([1, 2, 3])")
Marwan Tammam66aa4242019-07-24 06:56:08 -07001508 .testIfExactError("unsupported operand type(s) for |: 'int' and 'bool'", "2 | False");
Laurent Le Brun092f13b2015-08-24 14:50:00 +00001509 }
1510
1511 @Test
laurentlbc9b6f4a2017-06-21 11:58:50 +02001512 public void testSetIsNotIterable() throws Exception {
laurentlb9f9f5ec2019-11-15 10:37:49 -08001513 new SkylarkTest()
Googler8ac22102019-11-26 19:07:38 -08001514 .testIfErrorContains("not iterable", "list(depset(['a', 'b']))")
laurentlbc9b6f4a2017-06-21 11:58:50 +02001515 .testIfErrorContains("not iterable", "max(depset([1, 2, 3]))")
laurentlb0f5b7202017-06-23 16:55:01 +02001516 .testIfErrorContains("not iterable", "1 in depset([1, 2, 3])")
Googler8ac22102019-11-26 19:07:38 -08001517 .testIfErrorContains("not iterable", "sorted(depset(['a', 'b']))")
1518 .testIfErrorContains("not iterable", "tuple(depset(['a', 'b']))")
laurentlbc32efc82017-06-23 16:03:00 +02001519 .testIfErrorContains("not iterable", "[x for x in depset()]")
1520 .testIfErrorContains("not iterable", "len(depset(['a']))");
laurentlbc9b6f4a2017-06-21 11:58:50 +02001521 }
1522
1523 @Test
Googler084b64b2019-11-19 14:41:30 -08001524 public void testFieldReturnsNestedSet() throws Exception {
1525 update("mock", new MockClassObject());
1526 IllegalArgumentException e =
1527 assertThrows(IllegalArgumentException.class, () -> eval("mock.nset"));
1528 assertThat(e)
1529 .hasMessageThat()
1530 .contains(
adonovanb8eae2d2019-12-09 15:11:06 -08001531 "invalid Starlark value: class"
Googler084b64b2019-11-19 14:41:30 -08001532 + " com.google.devtools.build.lib.collect.nestedset.NestedSet");
Ulf Adams89f012d2015-02-26 13:39:28 +00001533 }
1534
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001535 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001536 public void testJavaFunctionReturnsNone() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001537 new SkylarkTest()
1538 .update("mock", new Mock())
1539 .setUp("v = mock.nullfunc_working()")
Googler641bdf72019-11-12 10:32:26 -08001540 .testLookup("v", Starlark.NONE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001541 }
1542
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001543 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001544 public void testVoidJavaFunctionReturnsNone() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001545 new SkylarkTest()
1546 .update("mock", new Mock())
1547 .setUp("v = mock.voidfunc()")
Googler641bdf72019-11-12 10:32:26 -08001548 .testLookup("v", Starlark.NONE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001549 }
1550
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001551 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001552 public void testAugmentedAssignment() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001553 new SkylarkTest().setUp("def f1(x):",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001554 " x += 1",
1555 " return x",
1556 "",
Florian Weikert28da3652015-07-01 14:52:30 +00001557 "foo = f1(41)").testLookup("foo", 42);
Ulf Adams89f012d2015-02-26 13:39:28 +00001558 }
1559
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001560 @Test
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001561 public void testAugmentedAssignmentHasNoSideEffects() throws Exception {
brandjon2b51f782017-07-25 21:05:04 +02001562 // Check object position.
Googlera3421e22019-09-26 06:48:32 -07001563 new SkylarkTest()
1564 .setUp(
1565 "counter = [0]",
1566 "value = [1, 2]",
1567 "",
1568 "def f():",
1569 " counter[0] = counter[0] + 1",
1570 " return value",
1571 "",
1572 "f()[1] += 1") // `f()` should be called only once here
Googler92578702019-11-21 12:19:31 -08001573 .testLookup("counter", StarlarkList.of(thread.mutability(), 1));
brandjon2b51f782017-07-25 21:05:04 +02001574
1575 // Check key position.
Googlera3421e22019-09-26 06:48:32 -07001576 new SkylarkTest()
1577 .setUp(
1578 "counter = [0]",
1579 "value = [1, 2]",
1580 "",
1581 "def f():",
1582 " counter[0] = counter[0] + 1",
1583 " return 1",
1584 "",
1585 "value[f()] += 1") // `f()` should be called only once here
Googler92578702019-11-21 12:19:31 -08001586 .testLookup("counter", StarlarkList.of(thread.mutability(), 1));
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001587 }
1588
1589 @Test
Googlerb6f33cd2019-09-16 10:32:03 -07001590 public void testInvalidAugmentedAssignment_ListExpression() throws Exception {
Googlerf0890f02019-10-01 07:28:48 -07001591 assertValidationError(
laurentlbe3684492017-08-21 12:02:46 +02001592 "cannot perform augmented assignment on a list or tuple expression",
Googlerf0890f02019-10-01 07:28:48 -07001593 //
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001594 "def f(a, b):",
1595 " [a, b] += []",
1596 "f(1, 2)");
1597 }
1598
Googlerf0890f02019-10-01 07:28:48 -07001599
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001600 @Test
brandjon2b51f782017-07-25 21:05:04 +02001601 public void testInvalidAugmentedAssignment_NotAnLValue() throws Exception {
Googlerf0890f02019-10-01 07:28:48 -07001602 assertValidationError(
1603 "cannot assign to 'x + 1'",
1604 //
1605 "x + 1 += 2");
brandjon2b51f782017-07-25 21:05:04 +02001606 }
1607
1608 @Test
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001609 public void testAssignmentEvaluationOrder() throws Exception {
Googlera3421e22019-09-26 06:48:32 -07001610 new SkylarkTest()
1611 .setUp(
1612 "ordinary = []",
1613 "augmented = []",
1614 "value = [1, 2]",
1615 "",
1616 "def f(record):",
1617 " record.append('f')",
1618 " return value",
1619 "",
1620 "def g(record):",
1621 " record.append('g')",
1622 " return value",
1623 "",
1624 "f(ordinary)[0] = g(ordinary)[1]",
1625 "f(augmented)[0] += g(augmented)[1]")
Googler92578702019-11-21 12:19:31 -08001626 .testLookup(
1627 "ordinary", StarlarkList.of(thread.mutability(), "g", "f")) // This order is consistent
1628 .testLookup("augmented", StarlarkList.of(thread.mutability(), "f", "g")); // with Python
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001629 }
1630
1631 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001632 public void testDictComprehensions_IterationOrder() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001633 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001634 " d = {x : x for x in ['c', 'a', 'b']}",
1635 " s = ''",
1636 " for a in d:",
1637 " s += a",
1638 " return s",
Vladimir Moskva76e31d12016-12-05 16:28:37 +00001639 "s = foo()").testLookup("s", "cab");
Ulf Adams89f012d2015-02-26 13:39:28 +00001640 }
1641
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001642 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001643 public void testDotExpressionOnNonStructObject() throws Exception {
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001644 new SkylarkTest()
adonovan4e2b4952019-12-10 12:19:20 -08001645 .testIfExactError("'string' value has no field or method 'field'", "x = 'a'.field");
Ulf Adams89f012d2015-02-26 13:39:28 +00001646 }
1647
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001648 @Test
vladmos25da19d2017-05-04 18:00:59 +02001649 public void testPlusEqualsOnListMutating() throws Exception {
vladmosc5301e92017-12-08 03:07:47 -08001650 new SkylarkTest()
vladmos25da19d2017-05-04 18:00:59 +02001651 .setUp(
1652 "def func():",
1653 " l1 = [1, 2]",
1654 " l2 = l1",
1655 " l2 += [3, 4]",
1656 " return l1, l2",
1657 "lists = str(func())")
1658 .testLookup("lists", "([1, 2, 3, 4], [1, 2, 3, 4])");
1659
1660 // The same but with += after an IndexExpression
vladmosc5301e92017-12-08 03:07:47 -08001661 new SkylarkTest()
vladmos25da19d2017-05-04 18:00:59 +02001662 .setUp(
1663 "def func():",
1664 " l = [1, 2]",
1665 " d = {0: l}",
1666 " d[0] += [3, 4]",
1667 " return l, d[0]",
1668 "lists = str(func())")
1669 .testLookup("lists", "([1, 2, 3, 4], [1, 2, 3, 4])");
1670 }
1671
1672 @Test
1673 public void testPlusEqualsOnTuple() throws Exception {
vladmosc5301e92017-12-08 03:07:47 -08001674 new SkylarkTest()
vladmos25da19d2017-05-04 18:00:59 +02001675 .setUp(
1676 "def func():",
1677 " t1 = (1, 2)",
1678 " t2 = t1",
1679 " t2 += (3, 4)",
1680 " return t1, t2",
1681 "tuples = func()")
Googlercfd681f2019-11-11 07:24:02 -08001682 .testLookup("tuples", Tuple.of(Tuple.of(1, 2), Tuple.of(1, 2, 3, 4)));
vladmos25da19d2017-05-04 18:00:59 +02001683 }
1684
1685 @Test
vladmosee0a8bb2017-05-04 19:26:48 +02001686 public void testPlusOnDictDeprecated() throws Exception {
laurentlb3418cd52019-11-08 05:06:48 -08001687 new SkylarkTest()
vladmosee0a8bb2017-05-04 19:26:48 +02001688 .testIfErrorContains(
laurentlb3418cd52019-11-08 05:06:48 -08001689 "unsupported operand type(s) for +: 'dict' and 'dict'", "{1: 2} + {3: 4}");
1690 new SkylarkTest()
vladmosee0a8bb2017-05-04 19:26:48 +02001691 .testIfErrorContains(
laurentlb3418cd52019-11-08 05:06:48 -08001692 "unsupported operand type(s) for +: 'dict' and 'dict'",
vladmosee0a8bb2017-05-04 19:26:48 +02001693 "def func():",
1694 " d = {1: 2}",
1695 " d += {3: 4}",
1696 "func()");
1697 }
1698
1699 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001700 public void testDictAssignmentAsLValue() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001701 new SkylarkTest().setUp("def func():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001702 " d = {'a' : 1}",
1703 " d['b'] = 2",
1704 " return d",
Florian Weikert28da3652015-07-01 14:52:30 +00001705 "d = func()").testLookup("d", ImmutableMap.of("a", 1, "b", 2));
Ulf Adams89f012d2015-02-26 13:39:28 +00001706 }
1707
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001708 @Test
Vladimir Moskva10770382016-08-23 15:04:54 +00001709 public void testNestedDictAssignmentAsLValue() throws Exception {
1710 new SkylarkTest().setUp("def func():",
1711 " d = {'a' : 1}",
1712 " e = {'d': d}",
1713 " e['d']['b'] = 2",
1714 " return e",
1715 "e = func()").testLookup("e", ImmutableMap.of("d", ImmutableMap.of("a", 1, "b", 2)));
1716 }
1717
1718 @Test
1719 public void testListAssignmentAsLValue() throws Exception {
1720 new SkylarkTest().setUp("def func():",
1721 " a = [1, 2]",
1722 " a[1] = 3",
1723 " a[-2] = 4",
1724 " return a",
1725 "a = str(func())").testLookup("a", "[4, 3]");
1726 }
1727
1728 @Test
1729 public void testNestedListAssignmentAsLValue() throws Exception {
1730 new SkylarkTest().setUp("def func():",
1731 " d = [1, 2]",
1732 " e = [3, d]",
1733 " e[1][1] = 4",
1734 " return e",
1735 "e = str(func())").testLookup("e", "[3, [1, 4]]");
1736 }
cparsons6c1c0662018-02-05 02:01:28 -08001737
Vladimir Moskva10770382016-08-23 15:04:54 +00001738 @Test
Laurent Le Brund640bd32016-01-07 13:58:43 +00001739 public void testDictTupleAssignmentAsLValue() throws Exception {
1740 new SkylarkTest().setUp("def func():",
1741 " d = {'a' : 1}",
1742 " d['b'], d['c'] = 2, 3",
1743 " return d",
1744 "d = func()").testLookup("d", ImmutableMap.of("a", 1, "b", 2, "c", 3));
1745 }
1746
1747 @Test
1748 public void testDictItemPlusEqual() throws Exception {
1749 new SkylarkTest().setUp("def func():",
1750 " d = {'a' : 2}",
1751 " d['a'] += 3",
1752 " return d",
1753 "d = func()").testLookup("d", ImmutableMap.of("a", 5));
1754 }
1755
1756 @Test
Francois-Rene Rideauab049e02016-02-17 16:13:46 +00001757 public void testDictAssignmentAsLValueSideEffects() throws Exception {
Googlera9c93632019-11-13 10:48:07 -08001758 new SkylarkTest()
1759 .setUp("def func(d):", " d['b'] = 2", "d = {'a' : 1}", "func(d)")
Googler92578702019-11-21 12:19:31 -08001760 .testLookup("d", Dict.of((Mutability) null, "a", 1, "b", 2));
Ulf Adams89f012d2015-02-26 13:39:28 +00001761 }
1762
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001763 @Test
Francois-Rene Rideauef7a8a52016-01-29 17:37:48 +00001764 public void testAssignmentToListInDictSideEffect() throws Exception {
Googler942e1c42019-11-12 13:11:44 -08001765 new SkylarkTest()
1766 .setUp("l = [1, 2]", "d = {0: l}", "d[0].append(3)")
1767 .testLookup("l", StarlarkList.of(null, 1, 2, 3));
Francois-Rene Rideauef7a8a52016-01-29 17:37:48 +00001768 }
1769
1770 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001771 public void testUserFunctionKeywordArgs() throws Exception {
Francois-Rene Rideau676905a2015-08-31 15:39:09 +00001772 new SkylarkTest().setUp("def foo(a, b, c):",
Florian Weikert28da3652015-07-01 14:52:30 +00001773 " return a + b + c", "s = foo(1, c=2, b=3)")
1774 .testLookup("s", 6);
Ulf Adams89f012d2015-02-26 13:39:28 +00001775 }
1776
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001777 @Test
Laurent Le Brun68743162015-05-13 13:18:09 +00001778 public void testFunctionCallOrdering() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001779 new SkylarkTest().setUp("def func(): return foo() * 2",
Laurent Le Brun68743162015-05-13 13:18:09 +00001780 "def foo(): return 2",
Florian Weikert28da3652015-07-01 14:52:30 +00001781 "x = func()")
1782 .testLookup("x", 4);
Laurent Le Brun68743162015-05-13 13:18:09 +00001783 }
1784
1785 @Test
1786 public void testFunctionCallBadOrdering() throws Exception {
laurentlb3f4ee542018-09-11 05:41:26 -07001787 new SkylarkTest()
1788 .testIfErrorContains(
laurentlb3a979f72018-11-20 07:25:11 -08001789 "global variable 'foo' is referenced before assignment.",
laurentlb3f4ee542018-09-11 05:41:26 -07001790 "def func(): return foo() * 2",
1791 "x = func()",
1792 "def foo(): return 2");
Laurent Le Brun68743162015-05-13 13:18:09 +00001793 }
1794
1795 @Test
laurentlbcaafe302018-08-28 10:24:31 -07001796 public void testLocalVariableDefinedBelow() throws Exception {
laurentlb3f4ee542018-09-11 05:41:26 -07001797 new SkylarkTest()
laurentlbcaafe302018-08-28 10:24:31 -07001798 .setUp(
1799 "def beforeEven(li):", // returns the value before the first even number
1800 " for i in li:",
1801 " if i % 2 == 0:",
1802 " return a",
1803 " else:",
1804 " a = i",
1805 "res = beforeEven([1, 3, 4, 5])")
1806 .testLookup("res", 3);
1807 }
1808
1809 @Test
1810 public void testShadowisNotInitialized() throws Exception {
laurentlb2b3ad182018-12-05 05:49:45 -08001811 new SkylarkTest()
laurentlbcaafe302018-08-28 10:24:31 -07001812 .testIfErrorContains(
laurentlbebb40712018-08-29 11:54:27 -07001813 /* error message */ "local variable 'gl' is referenced before assignment",
laurentlbcaafe302018-08-28 10:24:31 -07001814 "gl = 5",
laurentlb3f4ee542018-09-11 05:41:26 -07001815 "def foo():",
laurentlbcaafe302018-08-28 10:24:31 -07001816 " if False: gl = 2",
1817 " return gl",
1818 "res = foo()");
1819 }
1820
1821 @Test
laurentlb3f4ee542018-09-11 05:41:26 -07001822 public void testShadowBuiltin() throws Exception {
laurentlb2b3ad182018-12-05 05:49:45 -08001823 new SkylarkTest()
laurentlbf6350622018-09-19 10:15:34 -07001824 .testIfErrorContains(
1825 "global variable 'len' is referenced before assignment",
1826 "x = len('abc')",
1827 "len = 2",
1828 "y = x + len");
1829 }
1830
1831 @Test
brandjon65fd1362017-10-22 19:49:35 +02001832 public void testFunctionCallRecursion() throws Exception {
1833 new SkylarkTest().testIfErrorContains("Recursion was detected when calling 'f' from 'g'",
1834 "def main():",
1835 " f(5)",
1836 "def f(n):",
1837 " if n > 0: g(n - 1)",
1838 "def g(n):",
1839 " if n > 0: f(n - 1)",
1840 "main()");
1841 }
1842
1843 @Test
Googlerf0890f02019-10-01 07:28:48 -07001844 // TODO(adonovan): move to Validation tests.
Laurent Le Brune102a2d2017-01-02 12:06:18 +00001845 public void testTypo() throws Exception {
Googlerf0890f02019-10-01 07:28:48 -07001846 assertValidationError(
1847 "name 'my_variable' is not defined (did you mean 'myVariable'?)",
1848 //
1849 "myVariable = 2",
1850 "x = my_variable + 1");
Laurent Le Brune102a2d2017-01-02 12:06:18 +00001851 }
1852
1853 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001854 public void testNoneTrueFalseInSkylark() throws Exception {
Googler641bdf72019-11-12 10:32:26 -08001855 new SkylarkTest()
1856 .setUp("a = None", "b = True", "c = False")
1857 .testLookup("a", Starlark.NONE)
1858 .testLookup("b", Boolean.TRUE)
1859 .testLookup("c", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001860 }
1861
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001862 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001863 public void testHasattrMethods() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001864 new SkylarkTest()
1865 .update("mock", new Mock())
1866 .setUp("a = hasattr(mock, 'struct_field')", "b = hasattr(mock, 'function')",
1867 "c = hasattr(mock, 'is_empty')", "d = hasattr('str', 'replace')",
1868 "e = hasattr(mock, 'other')\n")
1869 .testLookup("a", Boolean.TRUE)
1870 .testLookup("b", Boolean.TRUE)
1871 .testLookup("c", Boolean.TRUE)
1872 .testLookup("d", Boolean.TRUE)
1873 .testLookup("e", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001874 }
1875
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001876 @Test
cparsonse70aafe2018-02-28 12:16:38 -08001877 public void testGetattrMethods() throws Exception {
1878 new SkylarkTest()
1879 .update("mock", new Mock())
Marwan Tammama7b2b112019-07-24 03:45:55 -07001880 .setUp(
1881 "a = str(getattr(mock, 'struct_field', 'no'))",
1882 "b = str(getattr(mock, 'function', 'no'))",
1883 "c = str(getattr(mock, 'is_empty', 'no'))",
1884 "d = str(getattr('str', 'replace', 'no'))",
1885 "e = str(getattr(mock, 'other', 'no'))\n")
cparsonse70aafe2018-02-28 12:16:38 -08001886 .testLookup("a", "a")
Marwan Tammama7b2b112019-07-24 03:45:55 -07001887 .testLookup("b", "<built-in function function>")
1888 .testLookup("c", "<built-in function is_empty>")
1889 .testLookup("d", "<built-in function replace>")
cparsonse70aafe2018-02-28 12:16:38 -08001890 .testLookup("e", "no");
1891 }
1892
1893 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001894 public void testListAnTupleConcatenationDoesNotWorkInSkylark() throws Exception {
Francois-Rene Rideau93ed7f12015-10-20 15:39:33 +00001895 new SkylarkTest().testIfExactError("unsupported operand type(s) for +: 'list' and 'tuple'",
Francois-Rene Rideau4e994102015-09-17 22:41:28 +00001896 "[1, 2] + (3, 4)");
Ulf Adams89f012d2015-02-26 13:39:28 +00001897 }
1898
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001899 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001900 public void testCannotCreateMixedListInSkylark() throws Exception {
Laurent Le Brune083a912015-08-10 15:13:34 +00001901 new SkylarkTest().testExactOrder("['a', 'b', 1, 2]", "a", "b", 1, 2);
Ulf Adams89f012d2015-02-26 13:39:28 +00001902 }
1903
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001904 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001905 public void testCannotConcatListInSkylarkWithDifferentGenericTypes() throws Exception {
Laurent Le Brune083a912015-08-10 15:13:34 +00001906 new SkylarkTest().testExactOrder("[1, 2] + ['a', 'b']", 1, 2, "a", "b");
Ulf Adams89f012d2015-02-26 13:39:28 +00001907 }
1908
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001909 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001910 public void testConcatEmptyListWithNonEmptyWorks() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001911 new SkylarkTest().testExactOrder("[] + ['a', 'b']", "a", "b");
Ulf Adams89f012d2015-02-26 13:39:28 +00001912 }
1913
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001914 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001915 public void testFormatStringWithTuple() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001916 new SkylarkTest().setUp("v = '%s%s' % ('a', 1)").testLookup("v", "a1");
Ulf Adams89f012d2015-02-26 13:39:28 +00001917 }
1918
Francois-Rene Rideaue8cfead2015-03-17 16:01:47 +00001919 @Test
1920 public void testSingletonTuple() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001921 new SkylarkTest().testExactOrder("(1,)", 1);
Francois-Rene Rideaue8cfead2015-03-17 16:01:47 +00001922 }
1923
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001924 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001925 public void testDirFindsClassObjectFields() throws Exception {
Laurent Le Brun8e965b82016-08-03 11:50:24 +00001926 new SkylarkTest().update("mock", new MockClassObject())
Florian Weikert28da3652015-07-01 14:52:30 +00001927 .testExactOrder("dir(mock)", "field", "nset");
Ulf Adams89f012d2015-02-26 13:39:28 +00001928 }
1929
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001930 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001931 public void testDirFindsJavaObjectStructFieldsAndMethods() throws Exception {
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001932 new SkylarkTest()
1933 .update("mock", new Mock())
1934 .testExactOrder(
1935 "dir(mock)",
1936 "function",
Benjamin Petersonbf1db782018-08-08 10:03:22 -07001937 "interrupted_struct_field",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001938 "is_empty",
cparsons4baafac2018-04-11 11:09:17 -07001939 "legacy_method",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001940 "nullfunc_failing",
1941 "nullfunc_working",
cparsons7520dcc2018-04-04 13:59:27 -07001942 "proxy_methods_object",
Benjamin Petersonaf53a112019-06-05 10:47:11 -07001943 "raise_unchecked_exception",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001944 "return_bad",
1945 "string",
1946 "string_list",
cparsonsaaab11f2018-01-31 11:00:11 -08001947 "string_list_dict",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001948 "struct_field",
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001949 "struct_field_callable",
cparsons07460fc2018-06-20 10:41:48 -07001950 "struct_field_with_extra",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001951 "value_of",
1952 "voidfunc",
cparsons979195e2018-04-09 15:43:22 -07001953 "with_args_and_kwargs",
Googlera3421e22019-09-26 06:48:32 -07001954 "with_args_and_thread",
cparsons5d446a72018-03-07 11:01:17 -08001955 "with_extra",
cparsons979195e2018-04-09 15:43:22 -07001956 "with_kwargs",
cparsons5d446a72018-03-07 11:01:17 -08001957 "with_params",
1958 "with_params_and_extra");
Ulf Adams89f012d2015-02-26 13:39:28 +00001959 }
1960
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001961 @Test
cparsons6c1c0662018-02-05 02:01:28 -08001962 public void testStrNativeInfo() throws Exception {
1963 new SkylarkTest()
1964 .update("mock", new NativeInfoMock())
1965 .testEval(
1966 "str(mock)",
1967 "'struct(struct_field_callable = <built-in function foobar>, struct_field_none = None, "
1968 + "struct_field_string = \"a\")'");
1969 }
1970
1971 @Test
1972 public void testDirNativeInfo() throws Exception {
1973 new SkylarkTest()
1974 .update("mock", new NativeInfoMock())
1975 .testEval(
1976 "dir(mock)",
cparsons63c25552018-04-10 13:36:29 -07001977 "['callable_string', 'struct_field_callable', 'struct_field_none', "
Googler59245ca2019-12-02 15:44:53 -08001978 + "'struct_field_string', 'to_json', 'to_proto']")
1979 .testExpression("str(mock.to_json)", "<built-in function to_json>")
1980 .testExpression("str(getattr(mock, 'to_json'))", "<built-in function to_json>");
cparsons6c1c0662018-02-05 02:01:28 -08001981 }
1982
1983 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001984 public void testPrint() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001985 // TODO(fwe): cannot be handled by current testing suite
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001986 setFailFast(false);
Googler1a1fca22019-10-14 09:31:22 -07001987 exec("print('hello')");
vladmosa664a512017-08-10 20:30:17 +02001988 assertContainsDebug("hello");
Googler1a1fca22019-10-14 09:31:22 -07001989 exec("print('a', 'b')");
vladmosa664a512017-08-10 20:30:17 +02001990 assertContainsDebug("a b");
Googler1a1fca22019-10-14 09:31:22 -07001991 exec("print('a', 'b', sep='x')");
vladmosa664a512017-08-10 20:30:17 +02001992 assertContainsDebug("axb");
Ulf Adams89f012d2015-02-26 13:39:28 +00001993 }
1994
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001995 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001996 public void testPrintBadKwargs() throws Exception {
cparsons7ac265d2019-04-16 15:31:17 -07001997 new SkylarkTest()
1998 .testIfErrorContains(
1999 "unexpected keywords 'end', 'other', for call to function print(sep = \" \", *args)",
2000 "print(end='x', other='y')");
Ulf Adams89f012d2015-02-26 13:39:28 +00002001 }
2002
Ulf Adams89f012d2015-02-26 13:39:28 +00002003 // Override tests in EvaluationTest incompatible with Skylark
2004
2005 @SuppressWarnings("unchecked")
2006 @Override
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00002007 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00002008 public void testConcatLists() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00002009 new SkylarkTest().testExactOrder("[1,2] + [3,4]", 1, 2, 3, 4).testExactOrder("(1,2)", 1, 2)
2010 .testExactOrder("(1,2) + (3,4)", 1, 2, 3, 4);
2011
2012 // TODO(fwe): cannot be handled by current testing suite
Ulf Adams89f012d2015-02-26 13:39:28 +00002013 // list
2014 Object x = eval("[1,2] + [3,4]");
2015 assertThat((Iterable<Object>) x).containsExactly(1, 2, 3, 4).inOrder();
Ulf Adams89f012d2015-02-26 13:39:28 +00002016
2017 // tuple
2018 x = eval("(1,2)");
2019 assertThat((Iterable<Object>) x).containsExactly(1, 2).inOrder();
Googlercfd681f2019-11-11 07:24:02 -08002020 assertThat(x).isInstanceOf(Tuple.class);
Ulf Adams89f012d2015-02-26 13:39:28 +00002021
2022 x = eval("(1,2) + (3,4)");
2023 assertThat((Iterable<Object>) x).containsExactly(1, 2, 3, 4).inOrder();
Googlercfd681f2019-11-11 07:24:02 -08002024 assertThat(x).isInstanceOf(Tuple.class);
Ulf Adams89f012d2015-02-26 13:39:28 +00002025 }
2026
Ulf Adams89f012d2015-02-26 13:39:28 +00002027 @Override
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00002028 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00002029 public void testListConcatenation() throws Exception {}
2030
Florian Weikertf07e5442015-07-01 13:08:43 +00002031 @Override
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002032 @Test
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002033 public void testListComprehensionsMultipleVariablesFail() throws Exception {
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002034 new SkylarkTest()
2035 .testIfErrorContains(
brandjon2b51f782017-07-25 21:05:04 +02002036 "assignment length mismatch: left-hand side has length 3, but right-hand side "
2037 + "evaluates to value of length 2",
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002038 "def foo (): return [x + y for x, y, z in [(1, 2), (3, 4)]]",
2039 "foo()");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002040
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002041 new SkylarkTest()
2042 .testIfErrorContains(
Googler8ac22102019-11-26 19:07:38 -08002043 "type 'int' is not iterable", "def bar (): return [x + y for x, y in (1, 2)]", "bar()");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002044
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 "[x + y for x, y, z in [(1, 2), (3, 4)]]");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002050
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002051 new SkylarkTest()
Googler8ac22102019-11-26 19:07:38 -08002052 .testIfErrorContains("type 'int' is not iterable", "[x2 + y2 for x2, y2 in (1, 2)]");
laurentlb2db52702017-07-05 14:19:22 -04002053
2054 new SkylarkTest()
2055 // returns [2] in Python, it's an error in Skylark
brandjon2b51f782017-07-25 21:05:04 +02002056 .testIfErrorContains("must have at least one item", "[2 for [] in [()]]");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002057 }
2058
2059 @Override
2060 @Test
2061 public void testNotCallInt() throws Exception {
Googler1a1fca22019-10-14 09:31:22 -07002062 new SkylarkTest()
2063 .setUp("sum = 123456")
2064 .testLookup("sum", 123456)
Florian Weikert28da3652015-07-01 14:52:30 +00002065 .testIfExactError("'int' object is not callable", "sum(1, 2, 3, 4, 5, 6)")
Googler1a1fca22019-10-14 09:31:22 -07002066 .testExpression("sum", 123456);
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002067 }
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +00002068
2069 @Test
2070 public void testConditionalExpressionAtToplevel() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00002071 new SkylarkTest().setUp("x = 1 if 2 else 3").testLookup("x", 1);
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +00002072 }
2073
2074 @Test
2075 public void testConditionalExpressionInFunction() throws Exception {
Googler1a1fca22019-10-14 09:31:22 -07002076 new SkylarkTest()
2077 .setUp("def foo(a, b, c): return a+b if c else a-b\n")
2078 .testExpression("foo(23, 5, 0)", 18);
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +00002079 }
Michael Staib79bd2c22017-03-22 14:37:03 +00002080
adonovan7202d102019-12-09 13:58:57 -08002081 // This class extends NativeInfo (which provides @SkylarkCallable-annotated fields)
adonovan4e2b4952019-12-10 12:19:20 -08002082 // with additional fields from a map. The only production code that currently
2083 // does that is ToolchainInfo and its subclasses.
Michael Staib79bd2c22017-03-22 14:37:03 +00002084 @SkylarkModule(name = "SkylarkClassObjectWithSkylarkCallables", doc = "")
adonovan7202d102019-12-09 13:58:57 -08002085 private static final class SkylarkClassObjectWithSkylarkCallables extends NativeInfo {
2086
2087 static final NativeProvider<SkylarkClassObjectWithSkylarkCallables> CONSTRUCTOR =
dslomovde965ac2017-07-31 21:07:51 +02002088 new NativeProvider<SkylarkClassObjectWithSkylarkCallables>(
2089 SkylarkClassObjectWithSkylarkCallables.class, "struct_with_skylark_callables") {};
Michael Staib79bd2c22017-03-22 14:37:03 +00002090
adonovanf3a344e82019-12-11 11:10:11 -08002091 // A function that returns "fromValues".
2092 Object returnFromValues =
2093 new StarlarkCallable() {
2094 @Override
2095 public String getName() {
2096 return "returnFromValues";
2097 }
2098
2099 @Override
adonovan770606a2019-12-11 11:52:31 -08002100 public Object callImpl(
2101 StarlarkThread thread,
adonovanf3a344e82019-12-11 11:10:11 -08002102 FuncallExpression call,
adonovan770606a2019-12-11 11:52:31 -08002103 List<Object> args,
2104 Map<String, Object> kwargs) {
adonovanf3a344e82019-12-11 11:10:11 -08002105 return "fromValues";
2106 }
2107 };
2108
adonovan7202d102019-12-09 13:58:57 -08002109 final Map<String, Object> fields =
2110 ImmutableMap.of(
2111 "values_only_field",
2112 "fromValues",
2113 "values_only_method",
adonovanf3a344e82019-12-11 11:10:11 -08002114 returnFromValues,
adonovan7202d102019-12-09 13:58:57 -08002115 "collision_field",
2116 "fromValues",
2117 "collision_method",
adonovanf3a344e82019-12-11 11:10:11 -08002118 returnFromValues);
adonovan7202d102019-12-09 13:58:57 -08002119
Michael Staib79bd2c22017-03-22 14:37:03 +00002120 SkylarkClassObjectWithSkylarkCallables() {
adonovan7202d102019-12-09 13:58:57 -08002121 super(CONSTRUCTOR, Location.BUILTIN);
2122 }
Googler9eca6d52019-11-13 06:26:47 -08002123
adonovan7202d102019-12-09 13:58:57 -08002124 @Override
2125 public Object getValue(String name) throws EvalException {
2126 Object x = fields.get(name);
2127 return x != null ? x : super.getValue(name);
2128 }
Googler9eca6d52019-11-13 06:26:47 -08002129
adonovan7202d102019-12-09 13:58:57 -08002130 @Override
2131 public ImmutableCollection<String> getFieldNames() {
2132 return ImmutableSet.<String>builder()
2133 .addAll(fields.keySet())
2134 .addAll(super.getFieldNames())
2135 .build();
Michael Staib79bd2c22017-03-22 14:37:03 +00002136 }
2137
cparsons7f475d72018-03-30 13:54:46 -07002138 @SkylarkCallable(name = "callable_only_field", documented = false, structField = true)
Michael Staib79bd2c22017-03-22 14:37:03 +00002139 public String getCallableOnlyField() {
2140 return "fromSkylarkCallable";
2141 }
2142
cparsons7f475d72018-03-30 13:54:46 -07002143 @SkylarkCallable(name = "callable_only_method", documented = false, structField = false)
Michael Staib79bd2c22017-03-22 14:37:03 +00002144 public String getCallableOnlyMethod() {
2145 return "fromSkylarkCallable";
2146 }
2147
cparsons7f475d72018-03-30 13:54:46 -07002148 @SkylarkCallable(name = "collision_field", documented = false, structField = true)
Michael Staib79bd2c22017-03-22 14:37:03 +00002149 public String getCollisionField() {
2150 return "fromSkylarkCallable";
2151 }
2152
cparsons7f475d72018-03-30 13:54:46 -07002153 @SkylarkCallable(name = "collision_method", documented = false, structField = false)
Michael Staib79bd2c22017-03-22 14:37:03 +00002154 public String getCollisionMethod() {
2155 return "fromSkylarkCallable";
2156 }
2157 }
2158
2159 @Test
2160 public void testStructFieldDefinedOnlyInValues() throws Exception {
2161 new SkylarkTest()
2162 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2163 .setUp("v = val.values_only_field")
2164 .testLookup("v", "fromValues");
2165 }
2166
2167 @Test
2168 public void testStructMethodDefinedOnlyInValues() throws Exception {
2169 new SkylarkTest()
2170 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2171 .setUp("v = val.values_only_method()")
2172 .testLookup("v", "fromValues");
2173 }
2174
2175 @Test
2176 public void testStructFieldDefinedOnlyInSkylarkCallable() throws Exception {
2177 new SkylarkTest()
2178 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2179 .setUp("v = val.callable_only_field")
2180 .testLookup("v", "fromSkylarkCallable");
2181 }
2182
2183 @Test
2184 public void testStructMethodDefinedOnlyInSkylarkCallable() throws Exception {
2185 new SkylarkTest()
2186 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2187 .setUp("v = val.callable_only_method()")
2188 .testLookup("v", "fromSkylarkCallable");
2189 }
2190
adonovan4e2b4952019-12-10 12:19:20 -08002191
Michael Staib79bd2c22017-03-22 14:37:03 +00002192 @Test
Michael Staib79bd2c22017-03-22 14:37:03 +00002193 public void testStructMethodDefinedInValuesAndSkylarkCallable() throws Exception {
adonovan4e2b4952019-12-10 12:19:20 -08002194 // This test exercises the resolution of ambiguity between @SkylarkCallable-annotated
2195 // fields and those reported by ClassObject.getValue.
Michael Staib79bd2c22017-03-22 14:37:03 +00002196 new SkylarkTest()
2197 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2198 .setUp("v = val.collision_method()")
cparsonsda392932018-11-02 16:04:13 -07002199 .testLookup("v", "fromSkylarkCallable");
Michael Staib79bd2c22017-03-22 14:37:03 +00002200 }
2201
2202 @Test
2203 public void testStructFieldNotDefined() throws Exception {
2204 new SkylarkTest()
2205 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2206 .testIfExactError(
cparsons6c1c0662018-02-05 02:01:28 -08002207 // TODO(bazel-team): This should probably list callable_only_method as well.
adonovan4e2b4952019-12-10 12:19:20 -08002208 "'struct_with_skylark_callables' value has no field or method 'nonexistent_field'\n"
cparsons6c1c0662018-02-05 02:01:28 -08002209 + "Available attributes: callable_only_field, collision_field, collision_method, "
2210 + "values_only_field, values_only_method",
Michael Staib79bd2c22017-03-22 14:37:03 +00002211 "v = val.nonexistent_field");
2212 }
2213
2214 @Test
2215 public void testStructMethodNotDefined() throws Exception {
2216 new SkylarkTest()
2217 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2218 .testIfExactError(
adonovan4e2b4952019-12-10 12:19:20 -08002219 "'struct_with_skylark_callables' value has no field or method 'nonexistent_method'\n"
2220 + "Available attributes: callable_only_field, collision_field, collision_method, "
2221 + "values_only_field, values_only_method",
cparsons71b4dcc2018-10-24 13:46:37 -07002222 "v = val.nonexistent_method()");
Michael Staib79bd2c22017-03-22 14:37:03 +00002223 }
laurentlb9d5c0a02017-06-13 23:08:06 +02002224
2225 @Test
laurentlb9d5c0a02017-06-13 23:08:06 +02002226 public void testListComprehensionsShadowGlobalVariable() throws Exception {
Googler1a1fca22019-10-14 09:31:22 -07002227 exec(
2228 "a = 18", //
2229 "def foo():",
2230 " b = [a for a in range(3)]",
2231 " return a",
2232 "x = foo()");
laurentlb9d5c0a02017-06-13 23:08:06 +02002233 assertThat(lookup("x")).isEqualTo(18);
2234 }
2235
2236 @Test
cparsons645a35e2018-10-01 13:03:23 -07002237 public void testAnalysisFailureInfo() throws Exception {
2238 AnalysisFailure cause = new AnalysisFailure(Label.create("test", "test"), "ErrorMessage");
2239
cparsonse8d450c2018-10-04 16:01:53 -07002240 AnalysisFailureInfo info = AnalysisFailureInfo.forAnalysisFailures(ImmutableList.of(cause));
cparsons645a35e2018-10-01 13:03:23 -07002241
cparsons8ec36392018-11-19 11:16:26 -08002242 new SkylarkTest()
cparsons645a35e2018-10-01 13:03:23 -07002243 .update("val", info)
2244 .setUp(
2245 "causes = val.causes",
2246 "label = causes.to_list()[0].label",
2247 "message = causes.to_list()[0].message")
2248 .testLookup("label", Label.create("test", "test"))
2249 .testLookup("message", "ErrorMessage");
cparsons645a35e2018-10-01 13:03:23 -07002250 }
cparsons6622e6f2018-10-17 15:00:09 -07002251
2252 @Test
Googlerf0890f02019-10-01 07:28:48 -07002253 // TODO(adonovan): move to Validation tests.
cparsons6622e6f2018-10-17 15:00:09 -07002254 public void testExperimentalFlagGuardedValue() throws Exception {
2255 // This test uses an arbitrary experimental flag to verify this functionality. If this
2256 // experimental flag were to go away, this test may be updated to use any experimental flag.
2257 // The flag itself is unimportant to the test.
cparsons8ec36392018-11-19 11:16:26 -08002258 FlagGuardedValue val =
2259 FlagGuardedValue.onlyWhenExperimentalFlagIsTrue(
2260 FlagIdentifier.EXPERIMENTAL_BUILD_SETTING_API, "foo");
2261 String errorMessage =
2262 "GlobalSymbol is experimental and thus unavailable with the current "
2263 + "flags. It may be enabled by setting --experimental_build_setting_api";
cparsons6622e6f2018-10-17 15:00:09 -07002264
Googlerf0890f02019-10-01 07:28:48 -07002265
cparsons8ec36392018-11-19 11:16:26 -08002266 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=true")
cparsons6622e6f2018-10-17 15:00:09 -07002267 .setUp("var = GlobalSymbol")
2268 .testLookup("var", "foo");
2269
cparsons8ec36392018-11-19 11:16:26 -08002270 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=false")
2271 .testIfErrorContains(errorMessage, "var = GlobalSymbol");
cparsons6622e6f2018-10-17 15:00:09 -07002272
cparsons8ec36392018-11-19 11:16:26 -08002273 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=false")
2274 .testIfErrorContains(errorMessage, "def my_function():", " var = GlobalSymbol");
cparsons6622e6f2018-10-17 15:00:09 -07002275
cparsons8ec36392018-11-19 11:16:26 -08002276 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=false")
2277 .setUp("GlobalSymbol = 'other'", "var = GlobalSymbol")
cparsons6622e6f2018-10-17 15:00:09 -07002278 .testLookup("var", "other");
2279 }
2280
2281 @Test
2282 public void testIncompatibleFlagGuardedValue() throws Exception {
2283 // This test uses an arbitrary incompatible flag to verify this functionality. If this
2284 // incompatible flag were to go away, this test may be updated to use any incompatible flag.
2285 // The flag itself is unimportant to the test.
2286 FlagGuardedValue val = FlagGuardedValue.onlyWhenIncompatibleFlagIsFalse(
2287 FlagIdentifier.INCOMPATIBLE_NO_TARGET_OUTPUT_GROUP,
2288 "foo");
2289 String errorMessage = "GlobalSymbol is deprecated and will be removed soon. It may be "
2290 + "temporarily re-enabled by setting --incompatible_no_target_output_group=false";
2291
2292 new SkylarkTest(
2293 ImmutableMap.of("GlobalSymbol", val),
2294 "--incompatible_no_target_output_group=false")
2295 .setUp("var = GlobalSymbol")
2296 .testLookup("var", "foo");
2297
2298 new SkylarkTest(
2299 ImmutableMap.of("GlobalSymbol", val),
2300 "--incompatible_no_target_output_group=true")
2301 .testIfErrorContains(errorMessage,
2302 "var = GlobalSymbol");
2303
2304 new SkylarkTest(
2305 ImmutableMap.of("GlobalSymbol", val),
2306 "--incompatible_no_target_output_group=true")
2307 .testIfErrorContains(errorMessage,
2308 "def my_function():",
2309 " var = GlobalSymbol");
2310
2311 new SkylarkTest(
2312 ImmutableMap.of("GlobalSymbol", val),
2313 "--incompatible_no_target_output_group=true")
2314 .setUp("GlobalSymbol = 'other'",
2315 "var = GlobalSymbol")
2316 .testLookup("var", "other");
2317 }
adonovan4e2b4952019-12-10 12:19:20 -08002318
2319 @Test
2320 public void testFunctionEvaluatedBeforeArguments() throws Exception {
2321 // ''.nonesuch must be evaluated (and fail) before f().
2322 new SkylarkTest()
2323 .testIfErrorContains(
2324 "'string' value has no field or method 'nonesuch'",
2325 "def f(): x = 1//0",
2326 "''.nonesuch(f())");
2327 }
Ulf Adams89f012d2015-02-26 13:39:28 +00002328}