blob: de861169189ece89038f5a67a6772e38c6189b94 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2015 The Bazel Authors. All rights reserved.
Ulf Adams89f012d2015-02-26 13:39:28 +00002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.syntax;
15
16import static com.google.common.truth.Truth.assertThat;
Benjamin Petersonbf1db782018-08-08 10:03:22 -070017import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
cparsons979195e2018-04-09 15:43:22 -070018import static java.util.stream.Collectors.joining;
Ulf Adams89f012d2015-02-26 13:39:28 +000019
20import com.google.common.collect.ImmutableCollection;
21import com.google.common.collect.ImmutableList;
22import com.google.common.collect.ImmutableMap;
cparsons645a35e2018-10-01 13:03:23 -070023import com.google.devtools.build.lib.analysis.test.AnalysisFailure;
24import com.google.devtools.build.lib.analysis.test.AnalysisFailureInfo;
25import com.google.devtools.build.lib.cmdline.Label;
Ulf Adams89f012d2015-02-26 13:39:28 +000026import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
dslomov423dccc2017-04-11 12:18:09 +000027import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
cparsonse70aafe2018-02-28 12:16:38 -080028import com.google.devtools.build.lib.events.Location;
dslomovf1296572017-08-22 16:29:06 +020029import com.google.devtools.build.lib.packages.NativeInfo;
dslomovde965ac2017-07-31 21:07:51 +020030import com.google.devtools.build.lib.packages.NativeProvider;
cparsons0c5c1c62018-05-24 10:37:03 -070031import com.google.devtools.build.lib.packages.StructProvider;
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +000032import com.google.devtools.build.lib.skylarkinterface.Param;
Dmitry Lomovd22e1de2017-09-25 08:53:50 -040033import com.google.devtools.build.lib.skylarkinterface.ParamType;
John Field585d1a02015-12-16 16:03:52 +000034import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
Googlerab3cadc2019-11-08 15:17:21 -080035import com.google.devtools.build.lib.skylarkinterface.SkylarkGlobalLibrary;
John Field585d1a02015-12-16 16:03:52 +000036import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
dslomov423dccc2017-04-11 12:18:09 +000037import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
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() {
106 return CallUtils.getBuiltinCallable(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 = "")
Googlerab3cadc2019-11-08 15:17:21 -0800121 class Mock implements SkylarkValue {
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() {
149 return new Bad();
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() {
169 return CallUtils.getBuiltinCallable(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 }
181 @SuppressWarnings("unused")
cparsonse661f882018-06-28 10:12:05 -0700182 @SkylarkCallable(name = "nullfunc_failing",
183 parameters = {
184 @Param(name = "p1", type = String.class),
185 @Param(name = "p2", type = Integer.class),
186 },
187 documented = false, allowReturnNones = false)
dslomov423dccc2017-04-11 12:18:09 +0000188 public SkylarkValue nullfuncFailing(String p1, Integer p2) {
Ulf Adams89f012d2015-02-26 13:39:28 +0000189 return null;
190 }
cparsons7f475d72018-03-30 13:54:46 -0700191 @SkylarkCallable(name = "nullfunc_working", documented = false, allowReturnNones = true)
dslomov423dccc2017-04-11 12:18:09 +0000192 public SkylarkValue nullfuncWorking() {
Ulf Adams89f012d2015-02-26 13:39:28 +0000193 return null;
194 }
cparsons7f475d72018-03-30 13:54:46 -0700195 @SkylarkCallable(name = "voidfunc", documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000196 public void voidfunc() {}
cparsons7f475d72018-03-30 13:54:46 -0700197 @SkylarkCallable(name = "string_list", documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000198 public ImmutableList<String> stringList() {
199 return ImmutableList.<String>of("a", "b");
200 }
cparsons7f475d72018-03-30 13:54:46 -0700201 @SkylarkCallable(name = "string", documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000202 public String string() {
203 return "a";
204 }
cparsons7f475d72018-03-30 13:54:46 -0700205 @SkylarkCallable(name = "string_list_dict", documented = false)
cparsonsaaab11f2018-01-31 11:00:11 -0800206 public Map<String, List<String>> stringListDict() {
207 return ImmutableMap.of("a", ImmutableList.of("b", "c"));
208 }
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000209
cparsons4baafac2018-04-11 11:09:17 -0700210 @SkylarkCallable(
211 name = "legacy_method",
212 documented = false,
213 parameters = {
214 @Param(name = "pos", positional = true, type = Boolean.class),
215 @Param(name = "legacyNamed", type = Boolean.class, positional = true, named = false,
216 legacyNamed = true),
217 @Param(name = "named", type = Boolean.class, positional = false, named = true),
218 })
219 public String legacyMethod(Boolean pos, Boolean legacyNamed, Boolean named) {
220 return "legacy_method("
221 + pos
222 + ", "
223 + legacyNamed
224 + ", "
225 + named
226 + ")";
227 }
cparsons979195e2018-04-09 15:43:22 -0700228
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000229 @SkylarkCallable(
230 name = "with_params",
cparsons7f475d72018-03-30 13:54:46 -0700231 documented = false,
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000232 parameters = {
cparsons23aab172018-07-13 11:47:17 -0700233 @Param(name = "pos1"),
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000234 @Param(name = "pos2", defaultValue = "False", type = Boolean.class),
235 @Param(
236 name = "posOrNamed",
237 defaultValue = "False",
238 type = Boolean.class,
239 positional = true,
240 named = true
241 ),
242 @Param(name = "named", type = Boolean.class, positional = false, named = true),
243 @Param(
244 name = "optionalNamed",
245 type = Boolean.class,
246 defaultValue = "False",
247 positional = false,
248 named = true
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +0000249 ),
250 @Param(
251 name = "nonNoneable",
252 type = Object.class,
253 defaultValue = "\"a\"",
254 positional = false,
255 named = true
256 ),
257 @Param(
258 name = "noneable",
Googlere5da53c2016-09-21 12:34:44 +0000259 type = Integer.class,
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +0000260 defaultValue = "None",
261 noneable = true,
262 positional = false,
263 named = true
264 ),
Dmitry Lomovd22e1de2017-09-25 08:53:50 -0400265 @Param(
266 name = "multi",
267 allowedTypes = {
268 @ParamType(type = String.class),
269 @ParamType(type = Integer.class),
270 @ParamType(type = SkylarkList.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 }
278 )
279 public String withParams(
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +0000280 Integer pos1,
281 boolean pos2,
282 boolean posOrNamed,
283 boolean named,
284 boolean optionalNamed,
285 Object nonNoneable,
Dmitry Lomovd22e1de2017-09-25 08:53:50 -0400286 Object noneable,
287 Object multi) {
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000288 return "with_params("
289 + pos1
290 + ", "
291 + pos2
292 + ", "
293 + posOrNamed
294 + ", "
295 + named
296 + ", "
297 + optionalNamed
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +0000298 + ", "
cparsons5d446a72018-03-07 11:01:17 -0800299 + nonNoneable
Googler641bdf72019-11-12 10:32:26 -0800300 + (noneable != Starlark.NONE ? ", " + noneable : "")
301 + (multi != Starlark.NONE ? ", " + multi : "")
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +0000302 + ")";
303 }
304
cparsons5d446a72018-03-07 11:01:17 -0800305 @SkylarkCallable(
cparsonsb380dc92018-12-05 13:57:39 -0800306 name = "with_extra",
307 documented = false,
308 useLocation = true,
309 useAst = true,
Googlera3421e22019-09-26 06:48:32 -0700310 useStarlarkThread = true,
Googler7fa0dd22019-09-24 20:07:53 -0700311 useStarlarkSemantics = true)
cparsons5d446a72018-03-07 11:01:17 -0800312 public String withExtraInterpreterParams(
Googlera3421e22019-09-26 06:48:32 -0700313 Location location, FuncallExpression func, StarlarkThread thread, StarlarkSemantics sem) {
cparsons5d446a72018-03-07 11:01:17 -0800314 return "with_extra("
315 + location.getStartLine()
316 + ", "
317 + func.getArguments().size()
318 + ", "
Googlera3421e22019-09-26 06:48:32 -0700319 + thread.isGlobal()
cparsons73e10162018-03-22 10:02:02 -0700320 + ", "
321 + (sem != null)
cparsons5d446a72018-03-07 11:01:17 -0800322 + ")";
323 }
324
325 @SkylarkCallable(
laurentlb6659b4c2019-02-18 07:23:36 -0800326 name = "with_params_and_extra",
327 documented = false,
328 parameters = {
329 @Param(name = "pos1"),
330 @Param(name = "pos2", defaultValue = "False", type = Boolean.class),
331 @Param(
332 name = "posOrNamed",
333 defaultValue = "False",
334 type = Boolean.class,
335 positional = true,
336 named = true),
337 @Param(name = "named", type = Boolean.class, positional = false, named = true),
338 @Param(
339 name = "optionalNamed",
340 type = Boolean.class,
341 defaultValue = "False",
342 positional = false,
343 named = true),
344 @Param(
345 name = "nonNoneable",
346 type = Object.class,
347 defaultValue = "\"a\"",
348 positional = false,
349 named = true),
350 @Param(
351 name = "noneable",
352 type = Integer.class,
353 defaultValue = "None",
354 noneable = true,
355 positional = false,
356 named = true),
357 @Param(
358 name = "multi",
359 allowedTypes = {
360 @ParamType(type = String.class),
361 @ParamType(type = Integer.class),
362 @ParamType(type = SkylarkList.class, generic1 = Integer.class),
363 },
364 defaultValue = "None",
365 noneable = true,
366 positional = false,
367 named = true)
368 },
369 useAst = true,
370 useLocation = true,
Googlera3421e22019-09-26 06:48:32 -0700371 useStarlarkThread = true,
laurentlb28c30a72019-06-13 07:52:42 -0700372 useStarlarkSemantics = true)
cparsons5d446a72018-03-07 11:01:17 -0800373 public String withParamsAndExtraInterpreterParams(
374 Integer pos1,
375 boolean pos2,
376 boolean posOrNamed,
377 boolean named,
378 boolean optionalNamed,
379 Object nonNoneable,
380 Object noneable,
381 Object multi,
382 Location location,
383 FuncallExpression func,
Googlera3421e22019-09-26 06:48:32 -0700384 StarlarkThread thread,
laurentlb6659b4c2019-02-18 07:23:36 -0800385 StarlarkSemantics sem) {
cparsons5d446a72018-03-07 11:01:17 -0800386 return "with_params_and_extra("
387 + pos1
388 + ", "
389 + pos2
390 + ", "
391 + posOrNamed
392 + ", "
393 + named
394 + ", "
395 + optionalNamed
396 + ", "
397 + nonNoneable
Googler641bdf72019-11-12 10:32:26 -0800398 + (noneable != Starlark.NONE ? ", " + noneable : "")
399 + (multi != Starlark.NONE ? ", " + multi : "")
cparsons5d446a72018-03-07 11:01:17 -0800400 + ", "
401 + location.getStartLine()
402 + ", "
403 + func.getArguments().size()
404 + ", "
Googlera3421e22019-09-26 06:48:32 -0700405 + thread.isGlobal()
cparsons73e10162018-03-22 10:02:02 -0700406 + ", "
407 + (sem != null)
cparsons5d446a72018-03-07 11:01:17 -0800408 + ")";
409 }
410
cparsons7520dcc2018-04-04 13:59:27 -0700411 @SkylarkCallable(name = "proxy_methods_object",
412 doc = "Returns a struct containing all callable method objects of this mock",
413 allowReturnNones = true)
414 public ClassObject proxyMethodsObject() {
415 ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
Googler2e63b2a2019-11-11 08:59:12 -0800416 Starlark.addMethods(builder, this);
cparsons0c5c1c62018-05-24 10:37:03 -0700417 return StructProvider.STRUCT.create(builder.build(), "no native callable '%s'");
cparsons7520dcc2018-04-04 13:59:27 -0700418 }
419
cparsons979195e2018-04-09 15:43:22 -0700420 @SkylarkCallable(
Googlera3421e22019-09-26 06:48:32 -0700421 name = "with_args_and_thread",
422 documented = false,
423 parameters = {
424 @Param(name = "pos1", type = Integer.class),
425 @Param(name = "pos2", defaultValue = "False", type = Boolean.class),
426 @Param(name = "named", type = Boolean.class, positional = false, named = true),
427 },
428 extraPositionals = @Param(name = "args"),
429 useStarlarkThread = true)
430 public String withArgsAndThread(
431 Integer pos1, boolean pos2, boolean named, SkylarkList<?> args, StarlarkThread thread) {
cparsons979195e2018-04-09 15:43:22 -0700432 String argsString =
433 "args(" + args.stream().map(Printer::debugPrint).collect(joining(", ")) + ")";
Googlera3421e22019-09-26 06:48:32 -0700434 return "with_args_and_thread("
cparsons979195e2018-04-09 15:43:22 -0700435 + pos1
436 + ", "
437 + pos2
438 + ", "
439 + named
440 + ", "
441 + argsString
442 + ", "
Googlera3421e22019-09-26 06:48:32 -0700443 + thread.isGlobal()
cparsons979195e2018-04-09 15:43:22 -0700444 + ")";
445 }
446
447 @SkylarkCallable(
448 name = "with_kwargs",
449 documented = false,
450 parameters = {
451 @Param(name = "pos", defaultValue = "False", type = Boolean.class),
452 @Param(name = "named", type = Boolean.class, positional = false, named = true),
453 },
454 extraKeywords = @Param(name = "kwargs")
455 )
456 public String withKwargs(boolean pos, boolean named, SkylarkDict<?, ?> kwargs)
457 throws EvalException {
458 String kwargsString =
459 "kwargs("
460 + kwargs
461 .getContents(String.class, Object.class, "kwargs")
462 .entrySet()
463 .stream()
464 .map(entry -> entry.getKey() + "=" + entry.getValue())
465 .collect(joining(", "))
466 + ")";
467 return "with_kwargs(" + pos + ", " + named + ", " + kwargsString + ")";
468 }
469
470 @SkylarkCallable(
471 name = "with_args_and_kwargs",
472 documented = false,
473 parameters = {
474 @Param(name = "foo", named = true, positional = true, type = String.class),
475 },
476 extraPositionals = @Param(name = "args"),
477 extraKeywords = @Param(name = "kwargs")
478 )
479 public String withArgsAndKwargs(String foo, SkylarkList<?> args, SkylarkDict<?, ?> kwargs)
480 throws EvalException {
481 String argsString =
482 "args(" + args.stream().map(Printer::debugPrint).collect(joining(", ")) + ")";
483 String kwargsString =
484 "kwargs("
485 + kwargs
486 .getContents(String.class, Object.class, "kwargs")
487 .entrySet()
488 .stream()
489 .map(entry -> entry.getKey() + "=" + entry.getValue())
490 .collect(joining(", "))
491 + ")";
492 return "with_args_and_kwargs(" + foo + ", " + argsString + ", " + kwargsString + ")";
493 }
494
Benjamin Petersonaf53a112019-06-05 10:47:11 -0700495 @SkylarkCallable(name = "raise_unchecked_exception", documented = false)
496 public void raiseUncheckedException() {
497 throw new InternalError("buggy code");
498 }
499
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000500 @Override
501 public String toString() {
502 return "<mock>";
503 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000504 }
505
506 @SkylarkModule(name = "MockInterface", doc = "")
Googler93316322019-11-06 09:26:19 -0800507 static interface MockInterface extends SkylarkValue {
cparsonse661f882018-06-28 10:12:05 -0700508 @SkylarkCallable(name = "is_empty_interface",
509 parameters = { @Param(name = "str", type = String.class) },
510 documented = false)
Ulf Adams89f012d2015-02-26 13:39:28 +0000511 public Boolean isEmptyInterface(String str);
512 }
513
cparsons4dc97ff2018-05-24 13:48:22 -0700514 @SkylarkModule(name = "MockSubClass", doc = "")
Googlerab3cadc2019-11-08 15:17:21 -0800515 final class MockSubClass extends Mock implements MockInterface {
Ulf Adams89f012d2015-02-26 13:39:28 +0000516 @Override
517 public Boolean isEmpty(String str) {
518 return str.isEmpty();
519 }
520 @Override
521 public Boolean isEmptyInterface(String str) {
522 return str.isEmpty();
523 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000524 }
525
cparsons7f475d72018-03-30 13:54:46 -0700526 @SkylarkModule(name = "MockClassObject", documented = false, doc = "")
Googler93316322019-11-06 09:26:19 -0800527 static final class MockClassObject implements ClassObject, SkylarkValue {
Ulf Adams89f012d2015-02-26 13:39:28 +0000528 @Override
529 public Object getValue(String name) {
530 switch (name) {
531 case "field": return "a";
532 case "nset": return NestedSetBuilder.stableOrder().build();
vladmos3ad44e32017-05-04 18:30:51 +0200533 default: return null;
Ulf Adams89f012d2015-02-26 13:39:28 +0000534 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000535 }
536
537 @Override
brandjond331fa72017-12-28 07:38:31 -0800538 public ImmutableCollection<String> getFieldNames() {
Ulf Adams89f012d2015-02-26 13:39:28 +0000539 return ImmutableList.of("field", "nset");
540 }
541
542 @Override
brandjond331fa72017-12-28 07:38:31 -0800543 public String getErrorMessageForUnknownField(String name) {
Ulf Adams89f012d2015-02-26 13:39:28 +0000544 return null;
545 }
546 }
547
cparsonsd3d05b22018-05-24 12:12:07 -0700548 @SkylarkModule(name = "ParamterizedMock", doc = "")
Googler93316322019-11-06 09:26:19 -0800549 static interface ParameterizedApi<ObjectT> extends SkylarkValue {
cparsonsd3d05b22018-05-24 12:12:07 -0700550 @SkylarkCallable(
551 name = "method",
552 documented = false,
553 parameters = {
554 @Param(name = "foo", named = true, positional = true, type = Object.class),
555 }
556 )
557 public ObjectT method(ObjectT o);
558 }
559
560 static final class ParameterizedMock implements ParameterizedApi<String> {
561 @Override
562 public String method(String o) {
563 return o;
564 }
565 }
566
567 // Verifies that a method implementation overriding a parameterized annotated interface method
568 // is still treated as skylark-callable. Concretely, method() below should be treated as
569 // callable even though its method signature isn't an *exact* match of the annotated method
570 // declaration, due to the interface's method declaration being generic.
571 @Test
572 public void testParameterizedMock() throws Exception {
573 new SkylarkTest()
574 .update("mock", new ParameterizedMock())
575 .setUp("result = mock.method('bar')")
576 .testLookup("result", "bar");
Ulf Adams89f012d2015-02-26 13:39:28 +0000577 }
578
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000579 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000580 public void testSimpleIf() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000581 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000582 " a = 0",
583 " x = 0",
584 " if x: a = 5",
585 " return a",
Florian Weikert28da3652015-07-01 14:52:30 +0000586 "a = foo()").testLookup("a", 0);
Ulf Adams89f012d2015-02-26 13:39:28 +0000587 }
588
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000589 @Test
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000590 public void testIfPass() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000591 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000592 " a = 1",
593 " x = True",
594 " if x: pass",
595 " return a",
Florian Weikert28da3652015-07-01 14:52:30 +0000596 "a = foo()").testLookup("a", 1);
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000597 }
598
599 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000600 public void testNestedIf() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000601 executeNestedIf(0, 0, 0);
602 executeNestedIf(1, 0, 3);
603 executeNestedIf(1, 1, 5);
Ulf Adams89f012d2015-02-26 13:39:28 +0000604 }
605
Florian Weikert28da3652015-07-01 14:52:30 +0000606 private void executeNestedIf(int x, int y, int expected) throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000607 String fun = String.format("foo%s%s", x, y);
Florian Weikert28da3652015-07-01 14:52:30 +0000608 new SkylarkTest().setUp("def " + fun + "():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000609 " x = " + x,
610 " y = " + y,
611 " a = 0",
612 " b = 0",
613 " if x:",
614 " if y:",
615 " a = 2",
616 " b = 3",
617 " return a + b",
Florian Weikert28da3652015-07-01 14:52:30 +0000618 "x = " + fun + "()").testLookup("x", expected);
Ulf Adams89f012d2015-02-26 13:39:28 +0000619 }
620
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000621 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000622 public void testIfElse() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000623 executeIfElse("foo", "something", 2);
624 executeIfElse("bar", "", 3);
Ulf Adams89f012d2015-02-26 13:39:28 +0000625 }
626
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000627 private void executeIfElse(String fun, String y, int expected) throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000628 new SkylarkTest().setUp("def " + fun + "():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000629 " y = '" + y + "'",
630 " x = 5",
631 " if x:",
632 " if y: a = 2",
633 " else: a = 3",
Florian Weikert28da3652015-07-01 14:52:30 +0000634 " return a",
635 "z = " + fun + "()").testLookup("z", expected);
Ulf Adams89f012d2015-02-26 13:39:28 +0000636 }
637
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000638 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000639 public void testIfElifElse_IfExecutes() throws Exception {
640 execIfElifElse(1, 0, 1);
641 }
642
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000643 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000644 public void testIfElifElse_ElifExecutes() throws Exception {
645 execIfElifElse(0, 1, 2);
646 }
647
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000648 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000649 public void testIfElifElse_ElseExecutes() throws Exception {
650 execIfElifElse(0, 0, 3);
651 }
652
653 private void execIfElifElse(int x, int y, int v) throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000654 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000655 " x = " + x + "",
656 " y = " + y + "",
657 " if x:",
658 " return 1",
659 " elif y:",
660 " return 2",
661 " else:",
662 " return 3",
Florian Weikert28da3652015-07-01 14:52:30 +0000663 "v = foo()").testLookup("v", v);
Ulf Adams89f012d2015-02-26 13:39:28 +0000664 }
665
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000666 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000667 public void testForOnList() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000668 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000669 " s = ''",
670 " for i in ['hello', ' ', 'world']:",
671 " s = s + i",
672 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000673 "s = foo()").testLookup("s", "hello world");
Ulf Adams89f012d2015-02-26 13:39:28 +0000674 }
675
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000676 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000677 public void testForAssignmentList() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000678 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000679 " d = ['a', 'b', 'c']",
680 " s = ''",
681 " for i in d:",
682 " s = s + i",
Florian Weikert28da3652015-07-01 14:52:30 +0000683 " d = ['d', 'e', 'f']", // check that we use the old list
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000684 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000685 "s = foo()").testLookup("s", "abc");
Ulf Adams89f012d2015-02-26 13:39:28 +0000686 }
687
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000688 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000689 public void testForAssignmentDict() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000690 new SkylarkTest().setUp("def func():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000691 " d = {'a' : 1, 'b' : 2, 'c' : 3}",
692 " s = ''",
693 " for i in d:",
694 " s = s + i",
695 " d = {'d' : 1, 'e' : 2, 'f' : 3}",
696 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000697 "s = func()").testLookup("s", "abc");
Ulf Adams89f012d2015-02-26 13:39:28 +0000698 }
699
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000700 @Test
Jon Brandvein15775b22016-07-25 15:13:44 +0000701 public void testForUpdateList() throws Exception {
Jon Brandvein15775b22016-07-25 15:13:44 +0000702 new SkylarkTest().setUp("def foo():",
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000703 " xs = [1, 2, 3]",
Jon Brandvein15775b22016-07-25 15:13:44 +0000704 " for x in xs:",
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000705 " if x == 1:",
706 " xs.append(10)"
707 ).testIfErrorContains("trying to mutate a locked object", "foo()");
Jon Brandvein15775b22016-07-25 15:13:44 +0000708 }
709
710 @Test
711 public void testForUpdateDict() throws Exception {
Jon Brandvein15775b22016-07-25 15:13:44 +0000712 new SkylarkTest().setUp("def foo():",
713 " d = {'a': 1, 'b': 2, 'c': 3}",
Jon Brandvein15775b22016-07-25 15:13:44 +0000714 " for k in d:",
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000715 " d[k] *= 2"
716 ).testIfErrorContains("trying to mutate a locked object", "foo()");
717 }
718
719 @Test
720 public void testForUnlockedAfterBreak() throws Exception {
721 new SkylarkTest().setUp("def foo():",
722 " xs = [1, 2]",
723 " for x in xs:",
724 " break",
725 " xs.append(3)",
726 " return xs"
727 ).testEval("foo()", "[1, 2, 3]");
728 }
729
730 @Test
731 public void testForNestedOnSameListStillLocked() throws Exception {
732 new SkylarkTest().setUp("def foo():",
733 " xs = [1, 2]",
734 " ys = []",
735 " for x1 in xs:",
736 " for x2 in xs:",
737 " ys.append(x1 * x2)",
738 " xs.append(4)",
739 " return ys"
740 ).testIfErrorContains("trying to mutate a locked object", "foo()");
741 }
742
743 @Test
744 public void testForNestedOnSameListErrorMessage() throws Exception {
745 new SkylarkTest().setUp("def foo():",
746 " xs = [1, 2]",
747 " ys = []",
748 " for x1 in xs:",
749 " for x2 in xs:",
750 " ys.append(x1 * x2)",
751 " xs.append(4)",
752 " return ys"
753 // No file name in message, due to how test is set up.
Carmi Grushko46bf88c2017-02-20 22:37:15 +0000754 ).testIfErrorContains("Object locked at the following location(s): :4:3, :5:5", "foo()");
Jon Brandvein65e3ae62016-09-27 19:57:40 +0000755 }
756
757 @Test
758 public void testForNestedOnSameListUnlockedAtEnd() throws Exception {
759 new SkylarkTest().setUp("def foo():",
760 " xs = [1, 2]",
761 " ys = []",
762 " for x1 in xs:",
763 " for x2 in xs:",
764 " ys.append(x1 * x2)",
765 " xs.append(4)",
766 " return ys"
767 ).testEval("foo()", "[1, 2, 2, 4]");
768 }
769
770 @Test
771 public void testForNestedWithListCompGood() throws Exception {
772 new SkylarkTest().setUp("def foo():",
773 " xs = [1, 2]",
774 " ys = []",
775 " for x in xs:",
776 " zs = [None for x in xs for y in (ys.append(x) or ys)]",
777 " return ys"
778 ).testEval("foo()", "[1, 2, 1, 2]");
779 }
780 @Test
781 public void testForNestedWithListCompBad() throws Exception {
782 new SkylarkTest().setUp("def foo():",
783 " xs = [1, 2, 3]",
784 " ys = []",
785 " for x in xs:",
786 " zs = [None for x in xs for y in (xs.append(x) or ys)]",
787 " return ys"
788 ).testIfErrorContains("trying to mutate a locked object", "foo()");
Jon Brandvein15775b22016-07-25 15:13:44 +0000789 }
790
791 @Test
792 public void testForDeepUpdate() throws Exception {
793 // Check that indirectly reachable values can still be manipulated as normal.
Googler942e1c42019-11-12 13:11:44 -0800794 new SkylarkTest()
795 .setUp(
796 "def foo():",
797 " xs = [['a'], ['b'], ['c']]",
798 " ys = []",
799 " for x in xs:",
800 " for y in x:",
801 " ys.append(y)",
802 " xs[2].append(x[0])",
803 " return ys",
804 "ys = foo()")
805 .testLookup("ys", StarlarkList.of(null, "a", "b", "c", "a", "b"));
Jon Brandvein15775b22016-07-25 15:13:44 +0000806 }
807
808 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000809 public void testForNotIterable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000810 new SkylarkTest()
811 .update("mock", new Mock())
Florian Weikertc1d54ec2015-08-26 14:06:58 +0000812 .testIfErrorContains(
813 "type 'int' is not iterable",
814 "def func():",
815 " for i in mock.value_of('1'): a = i",
816 "func()\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000817 }
818
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000819 @Test
laurentlb26f843d2019-02-20 06:44:05 -0800820 public void testForStringNotIterable() throws Exception {
821 new SkylarkTest()
822 .update("mock", new Mock())
823 .testIfErrorContains(
824 "type 'string' is not iterable", "def func():", " for i in 'abc': a = i", "func()\n");
825 }
826
827 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000828 public void testForOnDictionary() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000829 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000830 " d = {1: 'a', 2: 'b', 3: 'c'}",
831 " s = ''",
832 " for i in d: s = s + d[i]",
833 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000834 "s = foo()").testLookup("s", "abc");
Ulf Adams89f012d2015-02-26 13:39:28 +0000835 }
836
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000837 @Test
Francois-Rene Rideau6c10eac2015-09-17 19:17:20 +0000838 public void testBadDictKey() throws Exception {
839 new SkylarkTest().testIfErrorContains(
840 "unhashable type: 'list'",
841 "{ [1, 2]: [3, 4] }");
842 }
843
844 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000845 public void testForLoopReuseVariable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000846 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000847 " s = ''",
848 " for i in ['a', 'b']:",
849 " for i in ['c', 'd']: s = s + i",
850 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000851 "s = foo()").testLookup("s", "cdcd");
Ulf Adams89f012d2015-02-26 13:39:28 +0000852 }
853
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000854 @Test
Laurent Le Brun741824b2015-03-20 15:10:19 +0000855 public void testForLoopMultipleVariables() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +0000856 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000857 " s = ''",
858 " for [i, j] in [[1, 2], [3, 4]]:",
859 " s = s + str(i) + str(j) + '.'",
860 " return s",
Florian Weikert28da3652015-07-01 14:52:30 +0000861 "s = foo()").testLookup("s", "12.34.");
Laurent Le Brun741824b2015-03-20 15:10:19 +0000862 }
863
864 @Test
Florian Weikert917ceaa2015-06-10 13:54:26 +0000865 public void testForLoopBreak() throws Exception {
866 simpleFlowTest("break", 1);
867 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000868
Florian Weikert917ceaa2015-06-10 13:54:26 +0000869 @Test
870 public void testForLoopContinue() throws Exception {
871 simpleFlowTest("continue", 10);
872 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000873
Florian Weikert917ceaa2015-06-10 13:54:26 +0000874 @SuppressWarnings("unchecked")
875 private void simpleFlowTest(String statement, int expected) throws Exception {
Googler1a1fca22019-10-14 09:31:22 -0700876 exec(
877 "def foo():",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000878 " s = 0",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000879 " hit = 0",
880 " for i in range(0, 10):",
881 " s = s + 1",
882 " " + statement + "",
883 " hit = 1",
884 " return [s, hit]",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000885 "x = foo()");
886 assertThat((Iterable<Object>) lookup("x")).containsExactly(expected, 0).inOrder();
887 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000888
889 @Test
Florian Weikert917ceaa2015-06-10 13:54:26 +0000890 public void testForLoopBreakFromDeeperBlock() throws Exception {
891 flowFromDeeperBlock("break", 1);
892 flowFromNestedBlocks("break", 29);
893 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000894
895 @Test
Florian Weikert917ceaa2015-06-10 13:54:26 +0000896 public void testForLoopContinueFromDeeperBlock() throws Exception {
897 flowFromDeeperBlock("continue", 5);
898 flowFromNestedBlocks("continue", 39);
899 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000900
Florian Weikert917ceaa2015-06-10 13:54:26 +0000901 private void flowFromDeeperBlock(String statement, int expected) throws Exception {
Googler1a1fca22019-10-14 09:31:22 -0700902 exec(
903 "def foo():",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000904 " s = 0",
905 " for i in range(0, 10):",
906 " if i % 2 != 0:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000907 " " + statement + "",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000908 " s = s + 1",
909 " return s",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000910 "x = foo()");
911 assertThat(lookup("x")).isEqualTo(expected);
912 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000913
Florian Weikert917ceaa2015-06-10 13:54:26 +0000914 private void flowFromNestedBlocks(String statement, int expected) throws Exception {
Googler1a1fca22019-10-14 09:31:22 -0700915 exec(
916 "def foo2():",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000917 " s = 0",
918 " for i in range(1, 41):",
919 " if i % 2 == 0:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000920 " if i % 3 == 0:",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000921 " if i % 5 == 0:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000922 " " + statement + "",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000923 " s = s + 1",
924 " return s",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000925 "y = foo2()");
926 assertThat(lookup("y")).isEqualTo(expected);
927 }
928
929 @Test
930 public void testNestedForLoopsMultipleBreaks() throws Exception {
931 nestedLoopsTest("break", 2, 6, 6);
932 }
933
934 @Test
935 public void testNestedForLoopsMultipleContinues() throws Exception {
936 nestedLoopsTest("continue", 4, 20, 20);
937 }
938
939 @SuppressWarnings("unchecked")
940 private void nestedLoopsTest(String statement, Integer outerExpected, int firstExpected,
941 int secondExpected) throws Exception {
Googler1a1fca22019-10-14 09:31:22 -0700942 exec(
943 "def foo():",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000944 " outer = 0",
945 " first = 0",
946 " second = 0",
947 " for i in range(0, 5):",
948 " for j in range(0, 5):",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000949 " if j == 2:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000950 " " + statement + "",
951 " first = first + 1",
952 " for k in range(0, 5):",
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000953 " if k == 2:",
Florian Weikert917ceaa2015-06-10 13:54:26 +0000954 " " + statement + "",
955 " second = second + 1",
956 " if i == 2:",
957 " " + statement + "",
958 " outer = outer + 1",
959 " return [outer, first, second]",
960 "x = foo()");
961 assertThat((Iterable<Object>) lookup("x"))
962 .containsExactly(outerExpected, firstExpected, secondExpected).inOrder();
963 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000964
Florian Weikert917ceaa2015-06-10 13:54:26 +0000965 @Test
966 public void testForLoopBreakError() throws Exception {
967 flowStatementInsideFunction("break");
968 flowStatementAfterLoop("break");
969 }
970
971 @Test
972 public void testForLoopContinueError() throws Exception {
973 flowStatementInsideFunction("continue");
974 flowStatementAfterLoop("continue");
975 }
976
Googlerf0890f02019-10-01 07:28:48 -0700977 // TODO(adonovan): move this and all tests that use it to Validation tests.
978 private void assertValidationError(String expectedError, final String... lines) throws Exception {
Googler1a1fca22019-10-14 09:31:22 -0700979 SyntaxError error = assertThrows(SyntaxError.class, () -> exec(lines));
Googlerf0890f02019-10-01 07:28:48 -0700980 assertThat(error).hasMessageThat().contains(expectedError);
981 }
982
Florian Weikert917ceaa2015-06-10 13:54:26 +0000983 private void flowStatementInsideFunction(String statement) throws Exception {
Googlerf0890f02019-10-01 07:28:48 -0700984 assertValidationError(
985 statement + " statement must be inside a for loop",
986 //
Florian Weikert917ceaa2015-06-10 13:54:26 +0000987 "def foo():",
brandjone5d95fb2017-07-13 17:23:09 +0200988 " " + statement,
Florian Weikert917ceaa2015-06-10 13:54:26 +0000989 "x = foo()");
990 }
Francois-Rene Rideau676905a2015-08-31 15:39:09 +0000991
Googlerf0890f02019-10-01 07:28:48 -0700992 private void flowStatementAfterLoop(String statement) throws Exception {
993 assertValidationError(
994 statement + " statement must be inside a for loop",
995 //
Florian Weikert917ceaa2015-06-10 13:54:26 +0000996 "def foo2():",
997 " for i in range(0, 3):",
998 " pass",
brandjone5d95fb2017-07-13 17:23:09 +0200999 " " + statement,
Florian Weikert917ceaa2015-06-10 13:54:26 +00001000 "y = foo2()");
1001 }
Florian Weikert28da3652015-07-01 14:52:30 +00001002
Florian Weikert917ceaa2015-06-10 13:54:26 +00001003 @Test
Googlerf0890f02019-10-01 07:28:48 -07001004 public void testStructMembersAreImmutable() throws Exception {
1005 assertValidationError("cannot assign to 's.x'", "s = struct(x = 'a')", "s.x = 'b'\n");
1006 }
1007
1008 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001009 public void testNoneAssignment() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001010 new SkylarkTest()
1011 .setUp("def foo(x=None):", " x = 1", " x = None", " return 2", "s = foo()")
1012 .testLookup("s", 2);
Ulf Adams89f012d2015-02-26 13:39:28 +00001013 }
1014
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001015 @Test
Laurent Le Brun88014fe2015-06-17 16:02:16 +00001016 public void testReassignment() throws Exception {
Googler1a1fca22019-10-14 09:31:22 -07001017 exec(
1018 "def foo(x=None):", //
Laurent Le Brun88014fe2015-06-17 16:02:16 +00001019 " x = 1",
1020 " x = [1, 2]",
1021 " x = 'str'",
1022 " return x",
1023 "s = foo()");
1024 assertThat(lookup("s")).isEqualTo("str");
1025 }
1026
1027 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001028 public void testJavaCalls() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001029 new SkylarkTest()
1030 .update("mock", new Mock())
1031 .setUp("b = mock.is_empty('a')")
1032 .testLookup("b", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001033 }
1034
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001035 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001036 public void testJavaCallsOnSubClass() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001037 new SkylarkTest()
1038 .update("mock", new MockSubClass())
1039 .setUp("b = mock.is_empty('a')")
1040 .testLookup("b", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001041 }
1042
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001043 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001044 public void testJavaCallsOnInterface() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001045 new SkylarkTest()
1046 .update("mock", new MockSubClass())
1047 .setUp("b = mock.is_empty_interface('a')")
1048 .testLookup("b", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001049 }
1050
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001051 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001052 public void testJavaCallsNotSkylarkCallable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001053 new SkylarkTest()
1054 .update("mock", new Mock())
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001055 .testIfExactError("type 'Mock' has no method value()", "mock.value()");
Laurent Le Brun648f8f32015-09-09 19:46:29 +00001056 }
1057
1058 @Test
1059 public void testNoOperatorIndex() throws Exception {
1060 new SkylarkTest()
1061 .update("mock", new Mock())
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001062 .testIfExactError("type 'Mock' has no operator [](int)", "mock[2]");
Ulf Adams89f012d2015-02-26 13:39:28 +00001063 }
1064
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001065 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001066 public void testJavaCallsNoMethod() throws Exception {
Francois-Rene Rideau676905a2015-08-31 15:39:09 +00001067 new SkylarkTest()
1068 .update("mock", new Mock())
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001069 .testIfExactError("type 'Mock' has no method bad()", "mock.bad()");
Ulf Adams89f012d2015-02-26 13:39:28 +00001070 }
1071
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001072 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001073 public void testJavaCallsNoMethodErrorMsg() throws Exception {
Laurent Le Brun648f8f32015-09-09 19:46:29 +00001074 new SkylarkTest()
cparsons03035142019-01-15 13:35:22 -08001075 .testIfExactError("type 'int' has no method bad()", "s = 3.bad('a', 'b', 'c')");
Ulf Adams89f012d2015-02-26 13:39:28 +00001076 }
1077
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001078 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001079 public void testJavaCallWithKwargs() throws Exception {
Francois-Rene Rideau676905a2015-08-31 15:39:09 +00001080 new SkylarkTest()
1081 .update("mock", new Mock())
cparsons03035142019-01-15 13:35:22 -08001082 .testIfExactError("type 'Mock' has no method isEmpty()", "mock.isEmpty(str='abc')");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001083 }
1084
cparsonsaaab11f2018-01-31 11:00:11 -08001085 @Test
1086 public void testStringListDictValues() throws Exception {
1087 new SkylarkTest()
1088 .update("mock", new Mock())
1089 .setUp(
1090 "def func(mock):",
1091 " for i, v in mock.string_list_dict().items():",
1092 " modified_list = v + ['extra_string']",
1093 " return modified_list",
1094 "m = func(mock)")
Googler942e1c42019-11-12 13:11:44 -08001095 .testLookup("m", StarlarkList.of(thread, "b", "c", "extra_string"));
cparsonsaaab11f2018-01-31 11:00:11 -08001096 }
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001097
1098 @Test
cparsons7520dcc2018-04-04 13:59:27 -07001099 public void testProxyMethodsObject() throws Exception {
1100 new SkylarkTest()
1101 .update("mock", new Mock())
1102 .setUp(
1103 "m = mock.proxy_methods_object()",
1104 "b = m.with_params(1, True, named=True)")
1105 .testLookup("b", "with_params(1, true, false, true, false, a)");
1106 }
1107
cparsons4baafac2018-04-11 11:09:17 -07001108 @Test
1109 public void testLegacyNamed() throws Exception {
cparsons65ecfea2019-08-28 14:37:23 -07001110 new SkylarkTest("--incompatible_restrict_named_params=false")
cparsons4baafac2018-04-11 11:09:17 -07001111 .update("mock", new Mock())
cparsons65ecfea2019-08-28 14:37:23 -07001112 .setUp("b = mock.legacy_method(True, legacyNamed=True, named=True)")
cparsons4baafac2018-04-11 11:09:17 -07001113 .testLookup("b", "legacy_method(true, true, true)");
1114
cparsons65ecfea2019-08-28 14:37:23 -07001115 new SkylarkTest("--incompatible_restrict_named_params=false")
cparsons4baafac2018-04-11 11:09:17 -07001116 .update("mock", new Mock())
cparsons65ecfea2019-08-28 14:37:23 -07001117 .setUp("b = mock.legacy_method(True, True, named=True)")
cparsons4baafac2018-04-11 11:09:17 -07001118 .testLookup("b", "legacy_method(true, true, true)");
1119
1120 // Verify legacyNamed also works with proxy method objects.
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())
1123 .setUp(
1124 "m = mock.proxy_methods_object()",
1125 "b = m.legacy_method(True, legacyNamed=True, named=True)")
1126 .testLookup("b", "legacy_method(true, true, true)");
1127
cparsons65ecfea2019-08-28 14:37:23 -07001128 new SkylarkTest("--incompatible_restrict_named_params=false")
cparsons4baafac2018-04-11 11:09:17 -07001129 .update("mock", new Mock())
cparsons65ecfea2019-08-28 14:37:23 -07001130 .setUp("m = mock.proxy_methods_object()", "b = m.legacy_method(True, True, named=True)")
cparsons4baafac2018-04-11 11:09:17 -07001131 .testLookup("b", "legacy_method(true, true, true)");
1132 }
1133
cparsons74f78972018-04-06 12:55:47 -07001134 /**
1135 * This test verifies an error is raised when a method parameter is set both positionally and
1136 * by name.
1137 */
1138 @Test
1139 public void testArgSpecifiedBothByNameAndPosition() throws Exception {
1140 // in with_params, 'posOrNamed' is positional parameter index 2. So by specifying both
1141 // posOrNamed by name and three positional parameters, there is a conflict.
1142 new SkylarkTest()
1143 .update("mock", new Mock())
1144 .testIfErrorContains("got multiple values for keyword argument 'posOrNamed'",
1145 "mock.with_params(1, True, True, posOrNamed=True, named=True)");
1146 }
1147
1148 @Test
1149 public void testTooManyPositionalArgs() throws Exception {
1150 new SkylarkTest()
1151 .update("mock", new Mock())
1152 .testIfErrorContains("expected no more than 3 positional arguments, but got 4",
1153 "mock.with_params(1, True, True, 'toomany', named=True)");
1154
1155 new SkylarkTest()
1156 .update("mock", new Mock())
1157 .testIfErrorContains("expected no more than 3 positional arguments, but got 5",
1158 "mock.with_params(1, True, True, 'toomany', 'alsotoomany', named=True)");
1159
1160 new SkylarkTest()
1161 .update("mock", new Mock())
1162 .testIfErrorContains("expected no more than 1 positional arguments, but got 2",
1163 "mock.is_empty('a', 'b')");
1164 }
1165
cparsons7520dcc2018-04-04 13:59:27 -07001166 @Test
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001167 public void testJavaCallWithPositionalAndKwargs() throws Exception {
1168 new SkylarkTest()
1169 .update("mock", new Mock())
1170 .setUp("b = mock.with_params(1, True, named=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001171 .testLookup("b", "with_params(1, true, false, true, false, a)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001172 new SkylarkTest()
1173 .update("mock", new Mock())
Dmitry Lomovd22e1de2017-09-25 08:53:50 -04001174 .setUp("b = mock.with_params(1, True, named=True, multi=1)")
1175 .testLookup("b", "with_params(1, true, false, true, false, a, 1)");
1176 new SkylarkTest()
1177 .update("mock", new Mock())
1178 .setUp("b = mock.with_params(1, True, named=True, multi='abc')")
1179 .testLookup("b", "with_params(1, true, false, true, false, a, abc)");
1180
1181 new SkylarkTest()
1182 .update("mock", new Mock())
1183 .setUp("b = mock.with_params(1, True, named=True, multi=[1,2,3])")
1184 .testLookup("b", "with_params(1, true, false, true, false, a, [1, 2, 3])");
1185
1186 new SkylarkTest()
1187 .update("mock", new Mock())
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001188 .setUp("")
1189 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001190 "parameter 'named' has no default value, for call to "
1191 + "method with_params(pos1, pos2 = False, posOrNamed = False, named, "
1192 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1193 + "of 'Mock'",
Pedro Liberal Fernandez92f06a52016-09-28 07:33:42 +00001194 "mock.with_params(1, True)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001195 new SkylarkTest()
1196 .update("mock", new Mock())
1197 .setUp("")
1198 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001199 "parameter 'named' has no default value, for call to "
1200 + "method with_params(pos1, pos2 = False, posOrNamed = False, named, "
1201 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001202 + "of 'Mock'",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001203 "mock.with_params(1, True, True)");
1204 new SkylarkTest()
1205 .update("mock", new Mock())
1206 .setUp("b = mock.with_params(1, True, True, named=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001207 .testLookup("b", "with_params(1, true, true, true, false, a)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001208 new SkylarkTest()
1209 .update("mock", new Mock())
1210 .setUp("b = mock.with_params(1, True, named=True, posOrNamed=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001211 .testLookup("b", "with_params(1, true, true, true, false, a)");
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001212 new SkylarkTest()
1213 .update("mock", new Mock())
1214 .setUp("b = mock.with_params(1, True, named=True, posOrNamed=True, optionalNamed=True)")
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001215 .testLookup("b", "with_params(1, true, true, true, true, a)");
Pedro Liberal Fernandez837dbc12016-08-18 14:13:01 +00001216 new SkylarkTest()
1217 .update("mock", new Mock())
1218 .setUp("")
1219 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001220 "unexpected keyword 'n', for call to "
1221 + "method with_params(pos1, pos2 = False, posOrNamed = False, named, "
1222 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1223 + "of 'Mock'",
Pedro Liberal Fernandez837dbc12016-08-18 14:13:01 +00001224 "mock.with_params(1, True, named=True, posOrNamed=True, n=2)");
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001225 new SkylarkTest()
1226 .update("mock", new Mock())
1227 .setUp("")
1228 .testIfExactError(
cparsons03035142019-01-15 13:35:22 -08001229 "parameter 'nonNoneable' cannot be None, for call to method "
1230 + "with_params(pos1, pos2 = False, posOrNamed = False, named, "
1231 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1232 + "of 'Mock'",
Pedro Liberal Fernandezd0c5ff22016-08-18 18:53:46 +00001233 "mock.with_params(1, True, True, named=True, optionalNamed=False, nonNoneable=None)");
Dmitry Lomovd22e1de2017-09-25 08:53:50 -04001234
1235 new SkylarkTest()
1236 .update("mock", new Mock())
1237 .setUp("")
1238 .testIfExactError(
cparsonsa95884e2018-03-21 11:06:13 -07001239 "expected value of type 'string or int or sequence of ints or NoneType' for parameter"
cparsons03035142019-01-15 13:35:22 -08001240 + " 'multi', for call to method "
1241 + "with_params(pos1, pos2 = False, posOrNamed = False, named, "
1242 + "optionalNamed = False, nonNoneable = \"a\", noneable = None, multi = None) "
1243 + "of 'Mock'",
Dmitry Lomovd22e1de2017-09-25 08:53:50 -04001244 "mock.with_params(1, True, named=True, multi=False)");
1245
1246 // We do not enforce list item parameter type constraints.
1247 // Test for this behavior.
1248 new SkylarkTest()
1249 .update("mock", new Mock())
1250 .setUp("b = mock.with_params(1, True, named=True, multi=['a', 'b'])")
1251 .testLookup("b", "with_params(1, true, false, true, false, a, [\"a\", \"b\"])");
Ulf Adams89f012d2015-02-26 13:39:28 +00001252 }
1253
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001254 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001255 public void testNoJavaCallsWithoutSkylark() throws Exception {
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001256 new SkylarkTest().testIfExactError("type 'int' has no method to_string()", "s = 3.to_string()");
Laurent Le Brun648f8f32015-09-09 19:46:29 +00001257 }
Ulf Adams89f012d2015-02-26 13:39:28 +00001258
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001259 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001260 public void testStructAccess() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001261 new SkylarkTest()
1262 .update("mock", new Mock())
1263 .setUp("v = mock.struct_field")
1264 .testLookup("v", "a");
Ulf Adams89f012d2015-02-26 13:39:28 +00001265 }
1266
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001267 @Test
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001268 public void testStructAccessAsFuncallNonCallable() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001269 new SkylarkTest()
1270 .update("mock", new Mock())
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001271 .testIfExactError("'string' object is not callable", "v = mock.struct_field()");
1272 }
1273
1274 @Test
cparsons0e866862018-04-24 08:07:02 -07001275 public void testSelfCall() throws Exception {
1276 new SkylarkTest()
1277 .update("mock", new Mock())
1278 .setUp("v = mock('bestmock')")
1279 .testLookup("v", "I'm a mock named bestmock");
1280
1281 new SkylarkTest()
1282 .update("mock", new Mock())
1283 .setUp("mockfunction = mock", "v = mockfunction('bestmock')")
1284 .testLookup("v", "I'm a mock named bestmock");
1285
1286 new SkylarkTest()
1287 .update("mock", new Mock())
1288 .testIfErrorContains(
cparsons03035142019-01-15 13:35:22 -08001289 "expected value of type 'string' for parameter 'pos', for call to function MockFn(pos)",
cparsons0e866862018-04-24 08:07:02 -07001290 "v = mock(1)");
1291 }
1292
1293 @Test
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001294 public void testStructAccessAsFuncall() throws Exception {
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001295 new SkylarkTest()
1296 .update("mock", new Mock())
1297 .setUp("v = mock.struct_field_callable()")
1298 .testLookup("v", "foobar");
Ulf Adams89f012d2015-02-26 13:39:28 +00001299 }
1300
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001301 @Test
Benjamin Petersonbf1db782018-08-08 10:03:22 -07001302 public void testCallingInterruptedStructField() throws Exception {
1303 update("mock", new Mock());
1304 assertThrows(InterruptedException.class, () -> eval("mock.interrupted_struct_field()"));
1305 }
1306
1307 @Test
1308 public void testCallingInterruptedFunction() throws Exception {
Googlerab3cadc2019-11-08 15:17:21 -08001309 update("interrupted_function", CallUtils.getBuiltinCallable(this, "interrupted_function"));
Benjamin Petersonbf1db782018-08-08 10:03:22 -07001310 assertThrows(InterruptedException.class, () -> eval("interrupted_function()"));
1311 }
1312
1313 @Test
Benjamin Petersonaf53a112019-06-05 10:47:11 -07001314 public void testCallingMethodThatRaisesUncheckedException() throws Exception {
1315 update("mock", new Mock());
1316 assertThrows(InternalError.class, () -> eval("mock.raise_unchecked_exception()"));
1317 }
1318
1319 @Test
cparsons5d446a72018-03-07 11:01:17 -08001320 public void testJavaFunctionWithExtraInterpreterParams() throws Exception {
1321 new SkylarkTest()
1322 .update("mock", new Mock())
1323 .setUp("v = mock.with_extra()")
Googler7fa0dd22019-09-24 20:07:53 -07001324 .testLookup("v", "with_extra(1, 0, true, true)");
cparsons5d446a72018-03-07 11:01:17 -08001325 }
1326
1327 @Test
cparsons07460fc2018-06-20 10:41:48 -07001328 public void testStructFieldWithExtraInterpreterParams() throws Exception {
1329 new SkylarkTest()
1330 .update("mock", new Mock())
1331 .setUp("v = mock.struct_field_with_extra")
1332 .testLookup("v", "struct_field_with_extra(true)");
1333 }
1334
1335 @Test
cparsons5d446a72018-03-07 11:01:17 -08001336 public void testJavaFunctionWithParamsAndExtraInterpreterParams() throws Exception {
1337 new SkylarkTest()
1338 .update("mock", new Mock())
1339 .setUp("b = mock.with_params_and_extra(1, True, named=True)")
cparsons73e10162018-03-22 10:02:02 -07001340 .testLookup("b", "with_params_and_extra(1, true, false, true, false, a, 1, 3, true, true)");
cparsons5d446a72018-03-07 11:01:17 -08001341 }
1342
1343 @Test
Googlera3421e22019-09-26 06:48:32 -07001344 public void testJavaFunctionWithExtraArgsAndThread() throws Exception {
cparsons979195e2018-04-09 15:43:22 -07001345 new SkylarkTest()
1346 .update("mock", new Mock())
Googlera3421e22019-09-26 06:48:32 -07001347 .setUp("b = mock.with_args_and_thread(1, True, 'extraArg1', 'extraArg2', named=True)")
1348 .testLookup("b", "with_args_and_thread(1, true, true, args(extraArg1, extraArg2), true)");
cparsons979195e2018-04-09 15:43:22 -07001349
1350 // Use an args list.
1351 new SkylarkTest()
1352 .update("mock", new Mock())
1353 .setUp(
1354 "myargs = ['extraArg2']",
Googlera3421e22019-09-26 06:48:32 -07001355 "b = mock.with_args_and_thread(1, True, 'extraArg1', named=True, *myargs)")
1356 .testLookup("b", "with_args_and_thread(1, true, true, args(extraArg1, extraArg2), true)");
cparsons979195e2018-04-09 15:43:22 -07001357 }
1358
1359 @Test
1360 public void testJavaFunctionWithExtraKwargs() throws Exception {
1361 new SkylarkTest()
1362 .update("mock", new Mock())
1363 .setUp("b = mock.with_kwargs(True, extraKey1=True, named=True, extraKey2='x')")
1364 .testLookup("b", "with_kwargs(true, true, kwargs(extraKey1=true, extraKey2=x))");
1365
1366 // Use a kwargs dict.
1367 new SkylarkTest()
1368 .update("mock", new Mock())
1369 .setUp(
1370 "mykwargs = {'extraKey2':'x', 'named':True}",
1371 "b = mock.with_kwargs(True, extraKey1=True, **mykwargs)")
1372 .testLookup("b", "with_kwargs(true, true, kwargs(extraKey1=true, extraKey2=x))");
1373 }
1374
1375 @Test
1376 public void testJavaFunctionWithArgsAndKwargs() throws Exception {
1377 // Foo is used positionally
1378 new SkylarkTest()
1379 .update("mock", new Mock())
1380 .setUp("b = mock.with_args_and_kwargs('foo', 'bar', 'baz', extraKey1=True, extraKey2='x')")
1381 .testLookup(
1382 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey1=true, extraKey2=x))");
1383
1384 // Use an args list and a kwargs dict
1385 new SkylarkTest()
1386 .update("mock", new Mock())
1387 .setUp(
1388 "mykwargs = {'extraKey1':True}",
1389 "myargs = ['baz']",
1390 "b = mock.with_args_and_kwargs('foo', 'bar', extraKey2='x', *myargs, **mykwargs)")
1391 .testLookup(
1392 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey2=x, extraKey1=true))");
1393
1394 // Foo is used by name
1395 new SkylarkTest()
1396 .update("mock", new Mock())
1397 .setUp("b = mock.with_args_and_kwargs(foo='foo', extraKey1=True)")
1398 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs(extraKey1=true))");
1399
1400 // Empty args and kwargs.
1401 new SkylarkTest()
1402 .update("mock", new Mock())
1403 .setUp("b = mock.with_args_and_kwargs('foo')")
1404 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs())");
1405 }
1406
1407 @Test
1408 public void testProxyMethodsObjectWithArgsAndKwargs() throws Exception {
1409 // Foo is used positionally
1410 new SkylarkTest()
1411 .update("mock", new Mock())
1412 .setUp(
1413 "m = mock.proxy_methods_object()",
1414 "b = m.with_args_and_kwargs('foo', 'bar', 'baz', extraKey1=True, extraKey2='x')")
1415 .testLookup(
1416 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey1=true, extraKey2=x))");
1417
1418 // Use an args list and a kwargs dict
1419 new SkylarkTest()
1420 .update("mock", new Mock())
1421 .setUp(
1422 "mykwargs = {'extraKey1':True}",
1423 "myargs = ['baz']",
1424 "m = mock.proxy_methods_object()",
1425 "b = m.with_args_and_kwargs('foo', 'bar', extraKey2='x', *myargs, **mykwargs)")
1426 .testLookup(
1427 "b", "with_args_and_kwargs(foo, args(bar, baz), kwargs(extraKey2=x, extraKey1=true))");
1428
1429 // Foo is used by name
1430 new SkylarkTest()
1431 .update("mock", new Mock())
1432 .setUp(
1433 "m = mock.proxy_methods_object()",
1434 "b = m.with_args_and_kwargs(foo='foo', extraKey1=True)")
1435 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs(extraKey1=true))");
1436
1437 // Empty args and kwargs.
1438 new SkylarkTest()
1439 .update("mock", new Mock())
1440 .setUp("m = mock.proxy_methods_object()", "b = m.with_args_and_kwargs('foo')")
1441 .testLookup("b", "with_args_and_kwargs(foo, args(), kwargs())");
1442 }
1443
1444 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001445 public void testStructAccessOfMethod() throws Exception {
Googler1a1fca22019-10-14 09:31:22 -07001446 new SkylarkTest().update("mock", new Mock()).testExpression("type(mock.function)", "function");
1447 new SkylarkTest().update("mock", new Mock()).testExpression("mock.function()", "a");
Laurent Le Brun57badf42017-01-02 15:12:24 +00001448 }
1449
1450 @Test
1451 public void testStructAccessTypo() throws Exception {
1452 new SkylarkTest()
1453 .update("mock", new MockClassObject())
1454 .testIfExactError(
1455 "object of type 'MockClassObject' has no field 'fild' (did you mean 'field'?)",
1456 "mock.fild");
Ulf Adams89f012d2015-02-26 13:39:28 +00001457 }
1458
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001459 @Test
Googler055d6c62018-05-22 13:21:04 -07001460 public void testStructAccessType_nonClassObject() throws Exception {
1461 new SkylarkTest()
1462 .update("mock", new Mock())
1463 .testIfExactError(
1464 "object of type 'Mock' has no field 'sturct_field' (did you mean 'struct_field'?)",
1465 "v = mock.sturct_field");
1466 }
1467
1468 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001469 public void testJavaFunctionReturnsMutableObject() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001470 new SkylarkTest()
1471 .update("mock", new Mock())
1472 .testIfExactError(
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001473 "method 'return_bad' returns an object of invalid type Bad", "mock.return_bad()");
Ulf Adams89f012d2015-02-26 13:39:28 +00001474 }
1475
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001476 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001477 public void testJavaFunctionReturnsNullFails() throws Exception {
Benjamin Petersonaf53a112019-06-05 10:47:11 -07001478 update("mock", new Mock());
1479 IllegalStateException e =
1480 assertThrows(IllegalStateException.class, () -> eval("mock.nullfunc_failing('abc', 1)"));
1481 assertThat(e).hasMessageThat().contains("method invocation returned None");
Ulf Adams89f012d2015-02-26 13:39:28 +00001482 }
1483
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001484 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001485 public void testClassObjectAccess() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001486 new SkylarkTest()
1487 .update("mock", new MockClassObject())
1488 .setUp("v = mock.field")
1489 .testLookup("v", "a");
Ulf Adams89f012d2015-02-26 13:39:28 +00001490 }
1491
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001492 @Test
laurentlb32282e52019-05-21 15:48:20 -07001493 public void testInSetDeprecated() throws Exception {
1494 new SkylarkTest("--incompatible_depset_is_not_iterable=false")
Googler1a1fca22019-10-14 09:31:22 -07001495 .testExpression("'b' in depset(['a', 'b'])", Boolean.TRUE)
1496 .testExpression("'c' in depset(['a', 'b'])", Boolean.FALSE)
1497 .testExpression("1 in depset(['a', 'b'])", Boolean.FALSE);
Laurent Le Brunab0ca1a2015-03-31 17:13:25 +00001498 }
1499
1500 @Test
Laurent Le Brun092f13b2015-08-24 14:50:00 +00001501 public void testUnionSet() throws Exception {
laurentlb63c7ea62019-04-25 08:45:21 -07001502 new SkylarkTest("--incompatible_depset_union=false")
Googler1a1fca22019-10-14 09:31:22 -07001503 .testExpression("str(depset([1, 3]) | depset([1, 2]))", "depset([1, 2, 3])")
1504 .testExpression("str(depset([1, 2]) | [1, 3])", "depset([1, 2, 3])")
Marwan Tammam66aa4242019-07-24 06:56:08 -07001505 .testIfExactError("unsupported operand type(s) for |: 'int' and 'bool'", "2 | False");
Laurent Le Brun092f13b2015-08-24 14:50:00 +00001506 }
1507
1508 @Test
laurentlbc9b6f4a2017-06-21 11:58:50 +02001509 public void testSetIsNotIterable() throws Exception {
1510 new SkylarkTest("--incompatible_depset_is_not_iterable=true")
1511 .testIfErrorContains("not iterable", "list(depset(['a', 'b']))")
1512 .testIfErrorContains("not iterable", "max(depset([1, 2, 3]))")
laurentlb0f5b7202017-06-23 16:55:01 +02001513 .testIfErrorContains("not iterable", "1 in depset([1, 2, 3])")
laurentlbc9b6f4a2017-06-21 11:58:50 +02001514 .testIfErrorContains("not iterable", "sorted(depset(['a', 'b']))")
1515 .testIfErrorContains("not iterable", "tuple(depset(['a', 'b']))")
laurentlbc32efc82017-06-23 16:03:00 +02001516 .testIfErrorContains("not iterable", "[x for x in depset()]")
1517 .testIfErrorContains("not iterable", "len(depset(['a']))");
laurentlbc9b6f4a2017-06-21 11:58:50 +02001518 }
1519
1520 @Test
1521 public void testSetIsIterable() throws Exception {
1522 new SkylarkTest("--incompatible_depset_is_not_iterable=false")
Googler1a1fca22019-10-14 09:31:22 -07001523 .testExpression("str(list(depset(['a', 'b'])))", "[\"a\", \"b\"]")
1524 .testExpression("max(depset([1, 2, 3]))", 3)
1525 .testExpression("1 in depset([1, 2, 3])", true)
1526 .testExpression("str(sorted(depset(['b', 'a'])))", "[\"a\", \"b\"]")
1527 .testExpression("str(tuple(depset(['a', 'b'])))", "(\"a\", \"b\")")
1528 .testExpression("str([x for x in depset()])", "[]")
1529 .testExpression("len(depset(['a']))", 1);
laurentlbc9b6f4a2017-06-21 11:58:50 +02001530 }
1531
1532 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001533 public void testClassObjectCannotAccessNestedSet() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001534 new SkylarkTest()
1535 .update("mock", new MockClassObject())
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001536 .testIfErrorContains("internal error: type 'NestedSet' is not allowed", "v = mock.nset");
Ulf Adams89f012d2015-02-26 13:39:28 +00001537 }
1538
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001539 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001540 public void testJavaFunctionReturnsNone() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001541 new SkylarkTest()
1542 .update("mock", new Mock())
1543 .setUp("v = mock.nullfunc_working()")
Googler641bdf72019-11-12 10:32:26 -08001544 .testLookup("v", Starlark.NONE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001545 }
1546
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001547 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001548 public void testVoidJavaFunctionReturnsNone() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001549 new SkylarkTest()
1550 .update("mock", new Mock())
1551 .setUp("v = mock.voidfunc()")
Googler641bdf72019-11-12 10:32:26 -08001552 .testLookup("v", Starlark.NONE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001553 }
1554
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001555 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001556 public void testAugmentedAssignment() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001557 new SkylarkTest().setUp("def f1(x):",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001558 " x += 1",
1559 " return x",
1560 "",
Florian Weikert28da3652015-07-01 14:52:30 +00001561 "foo = f1(41)").testLookup("foo", 42);
Ulf Adams89f012d2015-02-26 13:39:28 +00001562 }
1563
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001564 @Test
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001565 public void testAugmentedAssignmentHasNoSideEffects() throws Exception {
brandjon2b51f782017-07-25 21:05:04 +02001566 // Check object position.
Googlera3421e22019-09-26 06:48:32 -07001567 new SkylarkTest()
1568 .setUp(
1569 "counter = [0]",
1570 "value = [1, 2]",
1571 "",
1572 "def f():",
1573 " counter[0] = counter[0] + 1",
1574 " return value",
1575 "",
1576 "f()[1] += 1") // `f()` should be called only once here
Googler942e1c42019-11-12 13:11:44 -08001577 .testLookup("counter", StarlarkList.of(thread, 1));
brandjon2b51f782017-07-25 21:05:04 +02001578
1579 // Check key position.
Googlera3421e22019-09-26 06:48:32 -07001580 new SkylarkTest()
1581 .setUp(
1582 "counter = [0]",
1583 "value = [1, 2]",
1584 "",
1585 "def f():",
1586 " counter[0] = counter[0] + 1",
1587 " return 1",
1588 "",
1589 "value[f()] += 1") // `f()` should be called only once here
Googler942e1c42019-11-12 13:11:44 -08001590 .testLookup("counter", StarlarkList.of(thread, 1));
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001591 }
1592
1593 @Test
Googlerb6f33cd2019-09-16 10:32:03 -07001594 public void testInvalidAugmentedAssignment_ListExpression() throws Exception {
Googlerf0890f02019-10-01 07:28:48 -07001595 assertValidationError(
laurentlbe3684492017-08-21 12:02:46 +02001596 "cannot perform augmented assignment on a list or tuple expression",
Googlerf0890f02019-10-01 07:28:48 -07001597 //
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001598 "def f(a, b):",
1599 " [a, b] += []",
1600 "f(1, 2)");
1601 }
1602
Googlerf0890f02019-10-01 07:28:48 -07001603
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001604 @Test
brandjon2b51f782017-07-25 21:05:04 +02001605 public void testInvalidAugmentedAssignment_NotAnLValue() throws Exception {
Googlerf0890f02019-10-01 07:28:48 -07001606 assertValidationError(
1607 "cannot assign to 'x + 1'",
1608 //
1609 "x + 1 += 2");
brandjon2b51f782017-07-25 21:05:04 +02001610 }
1611
1612 @Test
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001613 public void testAssignmentEvaluationOrder() throws Exception {
Googlera3421e22019-09-26 06:48:32 -07001614 new SkylarkTest()
1615 .setUp(
1616 "ordinary = []",
1617 "augmented = []",
1618 "value = [1, 2]",
1619 "",
1620 "def f(record):",
1621 " record.append('f')",
1622 " return value",
1623 "",
1624 "def g(record):",
1625 " record.append('g')",
1626 " return value",
1627 "",
1628 "f(ordinary)[0] = g(ordinary)[1]",
1629 "f(augmented)[0] += g(augmented)[1]")
Googler942e1c42019-11-12 13:11:44 -08001630 .testLookup("ordinary", StarlarkList.of(thread, "g", "f")) // This order is consistent
1631 .testLookup("augmented", StarlarkList.of(thread, "f", "g")); // with Python
Vladimir Moskva23ba4a82017-02-21 15:30:54 +00001632 }
1633
1634 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001635 public void testDictComprehensions_IterationOrder() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001636 new SkylarkTest().setUp("def foo():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001637 " d = {x : x for x in ['c', 'a', 'b']}",
1638 " s = ''",
1639 " for a in d:",
1640 " s += a",
1641 " return s",
Vladimir Moskva76e31d12016-12-05 16:28:37 +00001642 "s = foo()").testLookup("s", "cab");
Ulf Adams89f012d2015-02-26 13:39:28 +00001643 }
1644
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001645 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001646 public void testDotExpressionOnNonStructObject() throws Exception {
Laurent Le Brunc31f3512016-12-29 21:41:33 +00001647 new SkylarkTest()
Laurent Le Brun57badf42017-01-02 15:12:24 +00001648 .testIfExactError("object of type 'string' has no field 'field'", "x = 'a'.field");
Ulf Adams89f012d2015-02-26 13:39:28 +00001649 }
1650
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001651 @Test
vladmos25da19d2017-05-04 18:00:59 +02001652 public void testPlusEqualsOnListMutating() throws Exception {
vladmosc5301e92017-12-08 03:07:47 -08001653 new SkylarkTest()
vladmos25da19d2017-05-04 18:00:59 +02001654 .setUp(
1655 "def func():",
1656 " l1 = [1, 2]",
1657 " l2 = l1",
1658 " l2 += [3, 4]",
1659 " return l1, l2",
1660 "lists = str(func())")
1661 .testLookup("lists", "([1, 2, 3, 4], [1, 2, 3, 4])");
1662
1663 // The same but with += after an IndexExpression
vladmosc5301e92017-12-08 03:07:47 -08001664 new SkylarkTest()
vladmos25da19d2017-05-04 18:00:59 +02001665 .setUp(
1666 "def func():",
1667 " l = [1, 2]",
1668 " d = {0: l}",
1669 " d[0] += [3, 4]",
1670 " return l, d[0]",
1671 "lists = str(func())")
1672 .testLookup("lists", "([1, 2, 3, 4], [1, 2, 3, 4])");
1673 }
1674
1675 @Test
1676 public void testPlusEqualsOnTuple() throws Exception {
vladmosc5301e92017-12-08 03:07:47 -08001677 new SkylarkTest()
vladmos25da19d2017-05-04 18:00:59 +02001678 .setUp(
1679 "def func():",
1680 " t1 = (1, 2)",
1681 " t2 = t1",
1682 " t2 += (3, 4)",
1683 " return t1, t2",
1684 "tuples = func()")
Googlercfd681f2019-11-11 07:24:02 -08001685 .testLookup("tuples", Tuple.of(Tuple.of(1, 2), Tuple.of(1, 2, 3, 4)));
vladmos25da19d2017-05-04 18:00:59 +02001686 }
1687
1688 @Test
vladmosee0a8bb2017-05-04 19:26:48 +02001689 public void testPlusOnDictDeprecated() throws Exception {
laurentlb3418cd52019-11-08 05:06:48 -08001690 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'", "{1: 2} + {3: 4}");
1693 new SkylarkTest()
vladmosee0a8bb2017-05-04 19:26:48 +02001694 .testIfErrorContains(
laurentlb3418cd52019-11-08 05:06:48 -08001695 "unsupported operand type(s) for +: 'dict' and 'dict'",
vladmosee0a8bb2017-05-04 19:26:48 +02001696 "def func():",
1697 " d = {1: 2}",
1698 " d += {3: 4}",
1699 "func()");
1700 }
1701
1702 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001703 public void testDictAssignmentAsLValue() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001704 new SkylarkTest().setUp("def func():",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001705 " d = {'a' : 1}",
1706 " d['b'] = 2",
1707 " return d",
Florian Weikert28da3652015-07-01 14:52:30 +00001708 "d = func()").testLookup("d", ImmutableMap.of("a", 1, "b", 2));
Ulf Adams89f012d2015-02-26 13:39:28 +00001709 }
1710
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001711 @Test
Vladimir Moskva10770382016-08-23 15:04:54 +00001712 public void testNestedDictAssignmentAsLValue() throws Exception {
1713 new SkylarkTest().setUp("def func():",
1714 " d = {'a' : 1}",
1715 " e = {'d': d}",
1716 " e['d']['b'] = 2",
1717 " return e",
1718 "e = func()").testLookup("e", ImmutableMap.of("d", ImmutableMap.of("a", 1, "b", 2)));
1719 }
1720
1721 @Test
1722 public void testListAssignmentAsLValue() throws Exception {
1723 new SkylarkTest().setUp("def func():",
1724 " a = [1, 2]",
1725 " a[1] = 3",
1726 " a[-2] = 4",
1727 " return a",
1728 "a = str(func())").testLookup("a", "[4, 3]");
1729 }
1730
1731 @Test
1732 public void testNestedListAssignmentAsLValue() throws Exception {
1733 new SkylarkTest().setUp("def func():",
1734 " d = [1, 2]",
1735 " e = [3, d]",
1736 " e[1][1] = 4",
1737 " return e",
1738 "e = str(func())").testLookup("e", "[3, [1, 4]]");
1739 }
cparsons6c1c0662018-02-05 02:01:28 -08001740
Vladimir Moskva10770382016-08-23 15:04:54 +00001741 @Test
Laurent Le Brund640bd32016-01-07 13:58:43 +00001742 public void testDictTupleAssignmentAsLValue() throws Exception {
1743 new SkylarkTest().setUp("def func():",
1744 " d = {'a' : 1}",
1745 " d['b'], d['c'] = 2, 3",
1746 " return d",
1747 "d = func()").testLookup("d", ImmutableMap.of("a", 1, "b", 2, "c", 3));
1748 }
1749
1750 @Test
1751 public void testDictItemPlusEqual() throws Exception {
1752 new SkylarkTest().setUp("def func():",
1753 " d = {'a' : 2}",
1754 " d['a'] += 3",
1755 " return d",
1756 "d = func()").testLookup("d", ImmutableMap.of("a", 5));
1757 }
1758
1759 @Test
Francois-Rene Rideauab049e02016-02-17 16:13:46 +00001760 public void testDictAssignmentAsLValueSideEffects() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001761 new SkylarkTest().setUp("def func(d):",
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001762 " d['b'] = 2",
1763 "d = {'a' : 1}",
Francois-Rene Rideauab049e02016-02-17 16:13:46 +00001764 "func(d)").testLookup("d", SkylarkDict.of(null, "a", 1, "b", 2));
Ulf Adams89f012d2015-02-26 13:39:28 +00001765 }
1766
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001767 @Test
Francois-Rene Rideauef7a8a52016-01-29 17:37:48 +00001768 public void testAssignmentToListInDictSideEffect() throws Exception {
Googler942e1c42019-11-12 13:11:44 -08001769 new SkylarkTest()
1770 .setUp("l = [1, 2]", "d = {0: l}", "d[0].append(3)")
1771 .testLookup("l", StarlarkList.of(null, 1, 2, 3));
Francois-Rene Rideauef7a8a52016-01-29 17:37:48 +00001772 }
1773
1774 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001775 public void testUserFunctionKeywordArgs() throws Exception {
Francois-Rene Rideau676905a2015-08-31 15:39:09 +00001776 new SkylarkTest().setUp("def foo(a, b, c):",
Florian Weikert28da3652015-07-01 14:52:30 +00001777 " return a + b + c", "s = foo(1, c=2, b=3)")
1778 .testLookup("s", 6);
Ulf Adams89f012d2015-02-26 13:39:28 +00001779 }
1780
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001781 @Test
Laurent Le Brun68743162015-05-13 13:18:09 +00001782 public void testFunctionCallOrdering() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001783 new SkylarkTest().setUp("def func(): return foo() * 2",
Laurent Le Brun68743162015-05-13 13:18:09 +00001784 "def foo(): return 2",
Florian Weikert28da3652015-07-01 14:52:30 +00001785 "x = func()")
1786 .testLookup("x", 4);
Laurent Le Brun68743162015-05-13 13:18:09 +00001787 }
1788
1789 @Test
1790 public void testFunctionCallBadOrdering() throws Exception {
laurentlb3f4ee542018-09-11 05:41:26 -07001791 new SkylarkTest()
1792 .testIfErrorContains(
laurentlb3a979f72018-11-20 07:25:11 -08001793 "global variable 'foo' is referenced before assignment.",
laurentlb3f4ee542018-09-11 05:41:26 -07001794 "def func(): return foo() * 2",
1795 "x = func()",
1796 "def foo(): return 2");
Laurent Le Brun68743162015-05-13 13:18:09 +00001797 }
1798
1799 @Test
laurentlbcaafe302018-08-28 10:24:31 -07001800 public void testLocalVariableDefinedBelow() throws Exception {
laurentlb3f4ee542018-09-11 05:41:26 -07001801 new SkylarkTest()
laurentlbcaafe302018-08-28 10:24:31 -07001802 .setUp(
1803 "def beforeEven(li):", // returns the value before the first even number
1804 " for i in li:",
1805 " if i % 2 == 0:",
1806 " return a",
1807 " else:",
1808 " a = i",
1809 "res = beforeEven([1, 3, 4, 5])")
1810 .testLookup("res", 3);
1811 }
1812
1813 @Test
1814 public void testShadowisNotInitialized() throws Exception {
laurentlb2b3ad182018-12-05 05:49:45 -08001815 new SkylarkTest()
laurentlbcaafe302018-08-28 10:24:31 -07001816 .testIfErrorContains(
laurentlbebb40712018-08-29 11:54:27 -07001817 /* error message */ "local variable 'gl' is referenced before assignment",
laurentlbcaafe302018-08-28 10:24:31 -07001818 "gl = 5",
laurentlb3f4ee542018-09-11 05:41:26 -07001819 "def foo():",
laurentlbcaafe302018-08-28 10:24:31 -07001820 " if False: gl = 2",
1821 " return gl",
1822 "res = foo()");
1823 }
1824
1825 @Test
laurentlb3f4ee542018-09-11 05:41:26 -07001826 public void testShadowBuiltin() throws Exception {
laurentlb2b3ad182018-12-05 05:49:45 -08001827 new SkylarkTest()
laurentlbf6350622018-09-19 10:15:34 -07001828 .testIfErrorContains(
1829 "global variable 'len' is referenced before assignment",
1830 "x = len('abc')",
1831 "len = 2",
1832 "y = x + len");
1833 }
1834
1835 @Test
brandjon65fd1362017-10-22 19:49:35 +02001836 public void testFunctionCallRecursion() throws Exception {
1837 new SkylarkTest().testIfErrorContains("Recursion was detected when calling 'f' from 'g'",
1838 "def main():",
1839 " f(5)",
1840 "def f(n):",
1841 " if n > 0: g(n - 1)",
1842 "def g(n):",
1843 " if n > 0: f(n - 1)",
1844 "main()");
1845 }
1846
1847 @Test
Googlerf0890f02019-10-01 07:28:48 -07001848 // TODO(adonovan): move to Validation tests.
Laurent Le Brune102a2d2017-01-02 12:06:18 +00001849 public void testTypo() throws Exception {
Googlerf0890f02019-10-01 07:28:48 -07001850 assertValidationError(
1851 "name 'my_variable' is not defined (did you mean 'myVariable'?)",
1852 //
1853 "myVariable = 2",
1854 "x = my_variable + 1");
Laurent Le Brune102a2d2017-01-02 12:06:18 +00001855 }
1856
1857 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001858 public void testNoneTrueFalseInSkylark() throws Exception {
Googler641bdf72019-11-12 10:32:26 -08001859 new SkylarkTest()
1860 .setUp("a = None", "b = True", "c = False")
1861 .testLookup("a", Starlark.NONE)
1862 .testLookup("b", Boolean.TRUE)
1863 .testLookup("c", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001864 }
1865
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001866 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001867 public void testHasattrMethods() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001868 new SkylarkTest()
1869 .update("mock", new Mock())
1870 .setUp("a = hasattr(mock, 'struct_field')", "b = hasattr(mock, 'function')",
1871 "c = hasattr(mock, 'is_empty')", "d = hasattr('str', 'replace')",
1872 "e = hasattr(mock, 'other')\n")
1873 .testLookup("a", Boolean.TRUE)
1874 .testLookup("b", Boolean.TRUE)
1875 .testLookup("c", Boolean.TRUE)
1876 .testLookup("d", Boolean.TRUE)
1877 .testLookup("e", Boolean.FALSE);
Ulf Adams89f012d2015-02-26 13:39:28 +00001878 }
1879
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001880 @Test
cparsonse70aafe2018-02-28 12:16:38 -08001881 public void testGetattrMethods() throws Exception {
1882 new SkylarkTest()
1883 .update("mock", new Mock())
Marwan Tammama7b2b112019-07-24 03:45:55 -07001884 .setUp(
1885 "a = str(getattr(mock, 'struct_field', 'no'))",
1886 "b = str(getattr(mock, 'function', 'no'))",
1887 "c = str(getattr(mock, 'is_empty', 'no'))",
1888 "d = str(getattr('str', 'replace', 'no'))",
1889 "e = str(getattr(mock, 'other', 'no'))\n")
cparsonse70aafe2018-02-28 12:16:38 -08001890 .testLookup("a", "a")
Marwan Tammama7b2b112019-07-24 03:45:55 -07001891 .testLookup("b", "<built-in function function>")
1892 .testLookup("c", "<built-in function is_empty>")
1893 .testLookup("d", "<built-in function replace>")
cparsonse70aafe2018-02-28 12:16:38 -08001894 .testLookup("e", "no");
1895 }
1896
1897 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001898 public void testListAnTupleConcatenationDoesNotWorkInSkylark() throws Exception {
Francois-Rene Rideau93ed7f12015-10-20 15:39:33 +00001899 new SkylarkTest().testIfExactError("unsupported operand type(s) for +: 'list' and 'tuple'",
Francois-Rene Rideau4e994102015-09-17 22:41:28 +00001900 "[1, 2] + (3, 4)");
Ulf Adams89f012d2015-02-26 13:39:28 +00001901 }
1902
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001903 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001904 public void testCannotCreateMixedListInSkylark() throws Exception {
Laurent Le Brune083a912015-08-10 15:13:34 +00001905 new SkylarkTest().testExactOrder("['a', 'b', 1, 2]", "a", "b", 1, 2);
Ulf Adams89f012d2015-02-26 13:39:28 +00001906 }
1907
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001908 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001909 public void testCannotConcatListInSkylarkWithDifferentGenericTypes() throws Exception {
Laurent Le Brune083a912015-08-10 15:13:34 +00001910 new SkylarkTest().testExactOrder("[1, 2] + ['a', 'b']", 1, 2, "a", "b");
Ulf Adams89f012d2015-02-26 13:39:28 +00001911 }
1912
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001913 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001914 public void testConcatEmptyListWithNonEmptyWorks() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001915 new SkylarkTest().testExactOrder("[] + ['a', 'b']", "a", "b");
Ulf Adams89f012d2015-02-26 13:39:28 +00001916 }
1917
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001918 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001919 public void testFormatStringWithTuple() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001920 new SkylarkTest().setUp("v = '%s%s' % ('a', 1)").testLookup("v", "a1");
Ulf Adams89f012d2015-02-26 13:39:28 +00001921 }
1922
Francois-Rene Rideaue8cfead2015-03-17 16:01:47 +00001923 @Test
1924 public void testSingletonTuple() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001925 new SkylarkTest().testExactOrder("(1,)", 1);
Francois-Rene Rideaue8cfead2015-03-17 16:01:47 +00001926 }
1927
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001928 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001929 public void testDirFindsClassObjectFields() throws Exception {
Laurent Le Brun8e965b82016-08-03 11:50:24 +00001930 new SkylarkTest().update("mock", new MockClassObject())
Florian Weikert28da3652015-07-01 14:52:30 +00001931 .testExactOrder("dir(mock)", "field", "nset");
Ulf Adams89f012d2015-02-26 13:39:28 +00001932 }
1933
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001934 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001935 public void testDirFindsJavaObjectStructFieldsAndMethods() throws Exception {
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001936 new SkylarkTest()
1937 .update("mock", new Mock())
1938 .testExactOrder(
1939 "dir(mock)",
1940 "function",
Benjamin Petersonbf1db782018-08-08 10:03:22 -07001941 "interrupted_struct_field",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001942 "is_empty",
cparsons4baafac2018-04-11 11:09:17 -07001943 "legacy_method",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001944 "nullfunc_failing",
1945 "nullfunc_working",
cparsons7520dcc2018-04-04 13:59:27 -07001946 "proxy_methods_object",
Benjamin Petersonaf53a112019-06-05 10:47:11 -07001947 "raise_unchecked_exception",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001948 "return_bad",
1949 "string",
1950 "string_list",
cparsonsaaab11f2018-01-31 11:00:11 -08001951 "string_list_dict",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001952 "struct_field",
Vladimir Moskvaa5b16742016-10-31 14:09:41 +00001953 "struct_field_callable",
cparsons07460fc2018-06-20 10:41:48 -07001954 "struct_field_with_extra",
Damien Martin-Guillerez2d32c582016-08-04 14:29:18 +00001955 "value_of",
1956 "voidfunc",
cparsons979195e2018-04-09 15:43:22 -07001957 "with_args_and_kwargs",
Googlera3421e22019-09-26 06:48:32 -07001958 "with_args_and_thread",
cparsons5d446a72018-03-07 11:01:17 -08001959 "with_extra",
cparsons979195e2018-04-09 15:43:22 -07001960 "with_kwargs",
cparsons5d446a72018-03-07 11:01:17 -08001961 "with_params",
1962 "with_params_and_extra");
Ulf Adams89f012d2015-02-26 13:39:28 +00001963 }
1964
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001965 @Test
cparsons6c1c0662018-02-05 02:01:28 -08001966 public void testStrNativeInfo() throws Exception {
1967 new SkylarkTest()
1968 .update("mock", new NativeInfoMock())
1969 .testEval(
1970 "str(mock)",
1971 "'struct(struct_field_callable = <built-in function foobar>, struct_field_none = None, "
1972 + "struct_field_string = \"a\")'");
1973 }
1974
1975 @Test
1976 public void testDirNativeInfo() throws Exception {
1977 new SkylarkTest()
1978 .update("mock", new NativeInfoMock())
1979 .testEval(
1980 "dir(mock)",
cparsons63c25552018-04-10 13:36:29 -07001981 "['callable_string', 'struct_field_callable', 'struct_field_none', "
1982 + "'struct_field_string', 'to_json', 'to_proto']");
cparsons6c1c0662018-02-05 02:01:28 -08001983 }
1984
1985 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001986 public void testPrint() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00001987 // TODO(fwe): cannot be handled by current testing suite
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001988 setFailFast(false);
Googler1a1fca22019-10-14 09:31:22 -07001989 exec("print('hello')");
vladmosa664a512017-08-10 20:30:17 +02001990 assertContainsDebug("hello");
Googler1a1fca22019-10-14 09:31:22 -07001991 exec("print('a', 'b')");
vladmosa664a512017-08-10 20:30:17 +02001992 assertContainsDebug("a b");
Googler1a1fca22019-10-14 09:31:22 -07001993 exec("print('a', 'b', sep='x')");
vladmosa664a512017-08-10 20:30:17 +02001994 assertContainsDebug("axb");
Ulf Adams89f012d2015-02-26 13:39:28 +00001995 }
1996
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001997 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001998 public void testPrintBadKwargs() throws Exception {
cparsons7ac265d2019-04-16 15:31:17 -07001999 new SkylarkTest()
2000 .testIfErrorContains(
2001 "unexpected keywords 'end', 'other', for call to function print(sep = \" \", *args)",
2002 "print(end='x', other='y')");
Ulf Adams89f012d2015-02-26 13:39:28 +00002003 }
2004
Ulf Adams89f012d2015-02-26 13:39:28 +00002005 // Override tests in EvaluationTest incompatible with Skylark
2006
2007 @SuppressWarnings("unchecked")
2008 @Override
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00002009 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00002010 public void testConcatLists() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00002011 new SkylarkTest().testExactOrder("[1,2] + [3,4]", 1, 2, 3, 4).testExactOrder("(1,2)", 1, 2)
2012 .testExactOrder("(1,2) + (3,4)", 1, 2, 3, 4);
2013
2014 // TODO(fwe): cannot be handled by current testing suite
Ulf Adams89f012d2015-02-26 13:39:28 +00002015 // list
2016 Object x = eval("[1,2] + [3,4]");
2017 assertThat((Iterable<Object>) x).containsExactly(1, 2, 3, 4).inOrder();
Ulf Adams89f012d2015-02-26 13:39:28 +00002018
2019 // tuple
2020 x = eval("(1,2)");
2021 assertThat((Iterable<Object>) x).containsExactly(1, 2).inOrder();
Googlercfd681f2019-11-11 07:24:02 -08002022 assertThat(x).isInstanceOf(Tuple.class);
Ulf Adams89f012d2015-02-26 13:39:28 +00002023
2024 x = eval("(1,2) + (3,4)");
2025 assertThat((Iterable<Object>) x).containsExactly(1, 2, 3, 4).inOrder();
Googlercfd681f2019-11-11 07:24:02 -08002026 assertThat(x).isInstanceOf(Tuple.class);
Ulf Adams89f012d2015-02-26 13:39:28 +00002027 }
2028
Ulf Adams89f012d2015-02-26 13:39:28 +00002029 @Override
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00002030 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00002031 public void testListConcatenation() throws Exception {}
2032
Florian Weikertf07e5442015-07-01 13:08:43 +00002033 @Override
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002034 @Test
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002035 public void testListComprehensionsMultipleVariablesFail() throws Exception {
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002036 new SkylarkTest()
2037 .testIfErrorContains(
brandjon2b51f782017-07-25 21:05:04 +02002038 "assignment length mismatch: left-hand side has length 3, but right-hand side "
2039 + "evaluates to value of length 2",
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002040 "def foo (): return [x + y for x, y, z in [(1, 2), (3, 4)]]",
2041 "foo()");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002042
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002043 new SkylarkTest()
2044 .testIfErrorContains(
2045 "type 'int' is not a collection",
2046 "def bar (): return [x + y for x, y in (1, 2)]",
2047 "bar()");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002048
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002049 new SkylarkTest()
2050 .testIfErrorContains(
brandjon2b51f782017-07-25 21:05:04 +02002051 "assignment length mismatch: left-hand side has length 3, but right-hand side "
2052 + "evaluates to value of length 2",
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002053 "[x + y for x, y, z in [(1, 2), (3, 4)]]");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002054
Florian Weikertc1d54ec2015-08-26 14:06:58 +00002055 new SkylarkTest()
2056 .testIfErrorContains("type 'int' is not a collection", "[x2 + y2 for x2, y2 in (1, 2)]");
laurentlb2db52702017-07-05 14:19:22 -04002057
2058 new SkylarkTest()
2059 // returns [2] in Python, it's an error in Skylark
brandjon2b51f782017-07-25 21:05:04 +02002060 .testIfErrorContains("must have at least one item", "[2 for [] in [()]]");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002061 }
2062
2063 @Override
2064 @Test
2065 public void testNotCallInt() throws Exception {
Googler1a1fca22019-10-14 09:31:22 -07002066 new SkylarkTest()
2067 .setUp("sum = 123456")
2068 .testLookup("sum", 123456)
Florian Weikert28da3652015-07-01 14:52:30 +00002069 .testIfExactError("'int' object is not callable", "sum(1, 2, 3, 4, 5, 6)")
Googler1a1fca22019-10-14 09:31:22 -07002070 .testExpression("sum", 123456);
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00002071 }
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +00002072
2073 @Test
2074 public void testConditionalExpressionAtToplevel() throws Exception {
Florian Weikert28da3652015-07-01 14:52:30 +00002075 new SkylarkTest().setUp("x = 1 if 2 else 3").testLookup("x", 1);
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +00002076 }
2077
2078 @Test
2079 public void testConditionalExpressionInFunction() throws Exception {
Googler1a1fca22019-10-14 09:31:22 -07002080 new SkylarkTest()
2081 .setUp("def foo(a, b, c): return a+b if c else a-b\n")
2082 .testExpression("foo(23, 5, 0)", 18);
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +00002083 }
Michael Staib79bd2c22017-03-22 14:37:03 +00002084
2085 @SkylarkModule(name = "SkylarkClassObjectWithSkylarkCallables", doc = "")
dslomovf1296572017-08-22 16:29:06 +02002086 static final class SkylarkClassObjectWithSkylarkCallables extends NativeInfo {
dslomovde965ac2017-07-31 21:07:51 +02002087 private static final NativeProvider<SkylarkClassObjectWithSkylarkCallables> CONSTRUCTOR =
2088 new NativeProvider<SkylarkClassObjectWithSkylarkCallables>(
2089 SkylarkClassObjectWithSkylarkCallables.class, "struct_with_skylark_callables") {};
Michael Staib79bd2c22017-03-22 14:37:03 +00002090
2091 SkylarkClassObjectWithSkylarkCallables() {
2092 super(
2093 CONSTRUCTOR,
2094 ImmutableMap.of(
2095 "values_only_field",
2096 "fromValues",
2097 "values_only_method",
2098 new BuiltinFunction("values_only_method", FunctionSignature.of()) {
2099 public String invoke() {
2100 return "fromValues";
2101 }
2102 },
2103 "collision_field",
2104 "fromValues",
2105 "collision_method",
2106 new BuiltinFunction("collision_method", FunctionSignature.of()) {
2107 public String invoke() {
2108 return "fromValues";
2109 }
cparsonse70aafe2018-02-28 12:16:38 -08002110 }),
2111 Location.BUILTIN);
Michael Staib79bd2c22017-03-22 14:37:03 +00002112 }
2113
cparsons7f475d72018-03-30 13:54:46 -07002114 @SkylarkCallable(name = "callable_only_field", documented = false, structField = true)
Michael Staib79bd2c22017-03-22 14:37:03 +00002115 public String getCallableOnlyField() {
2116 return "fromSkylarkCallable";
2117 }
2118
cparsons7f475d72018-03-30 13:54:46 -07002119 @SkylarkCallable(name = "callable_only_method", documented = false, structField = false)
Michael Staib79bd2c22017-03-22 14:37:03 +00002120 public String getCallableOnlyMethod() {
2121 return "fromSkylarkCallable";
2122 }
2123
cparsons7f475d72018-03-30 13:54:46 -07002124 @SkylarkCallable(name = "collision_field", documented = false, structField = true)
Michael Staib79bd2c22017-03-22 14:37:03 +00002125 public String getCollisionField() {
2126 return "fromSkylarkCallable";
2127 }
2128
cparsons7f475d72018-03-30 13:54:46 -07002129 @SkylarkCallable(name = "collision_method", documented = false, structField = false)
Michael Staib79bd2c22017-03-22 14:37:03 +00002130 public String getCollisionMethod() {
2131 return "fromSkylarkCallable";
2132 }
2133 }
2134
2135 @Test
2136 public void testStructFieldDefinedOnlyInValues() throws Exception {
2137 new SkylarkTest()
2138 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2139 .setUp("v = val.values_only_field")
2140 .testLookup("v", "fromValues");
2141 }
2142
2143 @Test
2144 public void testStructMethodDefinedOnlyInValues() throws Exception {
2145 new SkylarkTest()
2146 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2147 .setUp("v = val.values_only_method()")
2148 .testLookup("v", "fromValues");
2149 }
2150
2151 @Test
2152 public void testStructFieldDefinedOnlyInSkylarkCallable() throws Exception {
2153 new SkylarkTest()
2154 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2155 .setUp("v = val.callable_only_field")
2156 .testLookup("v", "fromSkylarkCallable");
2157 }
2158
2159 @Test
2160 public void testStructMethodDefinedOnlyInSkylarkCallable() throws Exception {
2161 new SkylarkTest()
2162 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2163 .setUp("v = val.callable_only_method()")
2164 .testLookup("v", "fromSkylarkCallable");
2165 }
2166
2167 @Test
Michael Staib79bd2c22017-03-22 14:37:03 +00002168 public void testStructMethodDefinedInValuesAndSkylarkCallable() throws Exception {
2169 new SkylarkTest()
2170 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2171 .setUp("v = val.collision_method()")
cparsonsda392932018-11-02 16:04:13 -07002172 .testLookup("v", "fromSkylarkCallable");
Michael Staib79bd2c22017-03-22 14:37:03 +00002173 }
2174
2175 @Test
2176 public void testStructFieldNotDefined() throws Exception {
2177 new SkylarkTest()
2178 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2179 .testIfExactError(
cparsons6c1c0662018-02-05 02:01:28 -08002180 // TODO(bazel-team): This should probably list callable_only_method as well.
Michael Staib79bd2c22017-03-22 14:37:03 +00002181 "'struct_with_skylark_callables' object has no attribute 'nonexistent_field'\n"
cparsons6c1c0662018-02-05 02:01:28 -08002182 + "Available attributes: callable_only_field, collision_field, collision_method, "
2183 + "values_only_field, values_only_method",
Michael Staib79bd2c22017-03-22 14:37:03 +00002184 "v = val.nonexistent_field");
2185 }
2186
2187 @Test
2188 public void testStructMethodNotDefined() throws Exception {
2189 new SkylarkTest()
2190 .update("val", new SkylarkClassObjectWithSkylarkCallables())
2191 .testIfExactError(
2192 // TODO(bazel-team): This should probably match the error above better.
cparsons71b4dcc2018-10-24 13:46:37 -07002193 "type 'SkylarkClassObjectWithSkylarkCallables' has no method nonexistent_method()",
2194 "v = val.nonexistent_method()");
Michael Staib79bd2c22017-03-22 14:37:03 +00002195 }
laurentlb9d5c0a02017-06-13 23:08:06 +02002196
2197 @Test
laurentlb9d5c0a02017-06-13 23:08:06 +02002198 public void testListComprehensionsShadowGlobalVariable() throws Exception {
Googler1a1fca22019-10-14 09:31:22 -07002199 exec(
2200 "a = 18", //
2201 "def foo():",
2202 " b = [a for a in range(3)]",
2203 " return a",
2204 "x = foo()");
laurentlb9d5c0a02017-06-13 23:08:06 +02002205 assertThat(lookup("x")).isEqualTo(18);
2206 }
2207
2208 @Test
cparsons645a35e2018-10-01 13:03:23 -07002209 public void testAnalysisFailureInfo() throws Exception {
2210 AnalysisFailure cause = new AnalysisFailure(Label.create("test", "test"), "ErrorMessage");
2211
cparsonse8d450c2018-10-04 16:01:53 -07002212 AnalysisFailureInfo info = AnalysisFailureInfo.forAnalysisFailures(ImmutableList.of(cause));
cparsons645a35e2018-10-01 13:03:23 -07002213
cparsons8ec36392018-11-19 11:16:26 -08002214 new SkylarkTest()
cparsons645a35e2018-10-01 13:03:23 -07002215 .update("val", info)
2216 .setUp(
2217 "causes = val.causes",
2218 "label = causes.to_list()[0].label",
2219 "message = causes.to_list()[0].message")
2220 .testLookup("label", Label.create("test", "test"))
2221 .testLookup("message", "ErrorMessage");
cparsons645a35e2018-10-01 13:03:23 -07002222 }
cparsons6622e6f2018-10-17 15:00:09 -07002223
2224 @Test
Googlerf0890f02019-10-01 07:28:48 -07002225 // TODO(adonovan): move to Validation tests.
cparsons6622e6f2018-10-17 15:00:09 -07002226 public void testExperimentalFlagGuardedValue() throws Exception {
2227 // This test uses an arbitrary experimental flag to verify this functionality. If this
2228 // experimental flag were to go away, this test may be updated to use any experimental flag.
2229 // The flag itself is unimportant to the test.
cparsons8ec36392018-11-19 11:16:26 -08002230 FlagGuardedValue val =
2231 FlagGuardedValue.onlyWhenExperimentalFlagIsTrue(
2232 FlagIdentifier.EXPERIMENTAL_BUILD_SETTING_API, "foo");
2233 String errorMessage =
2234 "GlobalSymbol is experimental and thus unavailable with the current "
2235 + "flags. It may be enabled by setting --experimental_build_setting_api";
cparsons6622e6f2018-10-17 15:00:09 -07002236
Googlerf0890f02019-10-01 07:28:48 -07002237
cparsons8ec36392018-11-19 11:16:26 -08002238 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=true")
cparsons6622e6f2018-10-17 15:00:09 -07002239 .setUp("var = GlobalSymbol")
2240 .testLookup("var", "foo");
2241
cparsons8ec36392018-11-19 11:16:26 -08002242 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=false")
2243 .testIfErrorContains(errorMessage, "var = GlobalSymbol");
cparsons6622e6f2018-10-17 15:00:09 -07002244
cparsons8ec36392018-11-19 11:16:26 -08002245 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=false")
2246 .testIfErrorContains(errorMessage, "def my_function():", " var = GlobalSymbol");
cparsons6622e6f2018-10-17 15:00:09 -07002247
cparsons8ec36392018-11-19 11:16:26 -08002248 new SkylarkTest(ImmutableMap.of("GlobalSymbol", val), "--experimental_build_setting_api=false")
2249 .setUp("GlobalSymbol = 'other'", "var = GlobalSymbol")
cparsons6622e6f2018-10-17 15:00:09 -07002250 .testLookup("var", "other");
2251 }
2252
2253 @Test
2254 public void testIncompatibleFlagGuardedValue() throws Exception {
2255 // This test uses an arbitrary incompatible flag to verify this functionality. If this
2256 // incompatible flag were to go away, this test may be updated to use any incompatible flag.
2257 // The flag itself is unimportant to the test.
2258 FlagGuardedValue val = FlagGuardedValue.onlyWhenIncompatibleFlagIsFalse(
2259 FlagIdentifier.INCOMPATIBLE_NO_TARGET_OUTPUT_GROUP,
2260 "foo");
2261 String errorMessage = "GlobalSymbol is deprecated and will be removed soon. It may be "
2262 + "temporarily re-enabled by setting --incompatible_no_target_output_group=false";
2263
2264 new SkylarkTest(
2265 ImmutableMap.of("GlobalSymbol", val),
2266 "--incompatible_no_target_output_group=false")
2267 .setUp("var = GlobalSymbol")
2268 .testLookup("var", "foo");
2269
2270 new SkylarkTest(
2271 ImmutableMap.of("GlobalSymbol", val),
2272 "--incompatible_no_target_output_group=true")
2273 .testIfErrorContains(errorMessage,
2274 "var = GlobalSymbol");
2275
2276 new SkylarkTest(
2277 ImmutableMap.of("GlobalSymbol", val),
2278 "--incompatible_no_target_output_group=true")
2279 .testIfErrorContains(errorMessage,
2280 "def my_function():",
2281 " var = GlobalSymbol");
2282
2283 new SkylarkTest(
2284 ImmutableMap.of("GlobalSymbol", val),
2285 "--incompatible_no_target_output_group=true")
2286 .setUp("GlobalSymbol = 'other'",
2287 "var = GlobalSymbol")
2288 .testLookup("var", "other");
2289 }
Ulf Adams89f012d2015-02-26 13:39:28 +00002290}