blob: 7ad63460e2dd89ad5dabfb977f36f03643531189 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +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.
14
15package com.google.devtools.build.lib.skylark;
16
17import static com.google.common.truth.Truth.assertThat;
lberkiaea56b32017-05-30 12:35:33 +020018import static com.google.common.truth.Truth.assertWithMessage;
Florian Weikertb4c59042015-12-01 10:47:18 +000019import static org.junit.Assert.fail;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000020
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000021import com.google.common.collect.ImmutableList;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000022import com.google.common.collect.Iterables;
Rumou Duan33bab462016-04-25 17:55:12 +000023import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000024import com.google.devtools.build.lib.actions.Artifact;
Michajlo Matijkiw4a877382017-01-27 19:30:34 +000025import com.google.devtools.build.lib.actions.CompositeRunfilesSupplier;
26import com.google.devtools.build.lib.actions.RunfilesSupplier;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000027import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
Francois-Rene Rideau1bae01f2016-01-30 04:25:58 +000028import com.google.devtools.build.lib.analysis.ConfiguredTarget;
vladmos360fb4d2017-04-11 11:14:22 +000029import com.google.devtools.build.lib.analysis.DefaultProvider;
30import com.google.devtools.build.lib.analysis.FilesToRunProvider;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000031import com.google.devtools.build.lib.analysis.Runfiles;
32import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
33import com.google.devtools.build.lib.analysis.actions.SpawnAction;
34import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
35import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Substitution;
vladmos97d67082017-07-13 14:54:03 +020036import com.google.devtools.build.lib.cmdline.Label;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000037import com.google.devtools.build.lib.events.Event;
Vladimir Moskva748ba862016-09-20 13:46:11 +000038import com.google.devtools.build.lib.packages.SkylarkClassObject;
vladmos97d67082017-07-13 14:54:03 +020039import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor.SkylarkKey;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000040import com.google.devtools.build.lib.rules.SkylarkRuleContext;
41import com.google.devtools.build.lib.skylark.util.SkylarkTestCase;
Damien Martin-Guillerez2ca9b722016-06-09 17:43:55 +000042import com.google.devtools.build.lib.skylarkinterface.Param;
John Field585d1a02015-12-16 16:03:52 +000043import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000044import com.google.devtools.build.lib.syntax.BuiltinFunction;
Francois-Rene Rideauab049e02016-02-17 16:13:46 +000045import com.google.devtools.build.lib.syntax.Environment;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000046import com.google.devtools.build.lib.syntax.EvalException;
47import com.google.devtools.build.lib.syntax.EvalUtils;
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +000048import com.google.devtools.build.lib.syntax.Printer;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000049import com.google.devtools.build.lib.syntax.Runtime;
50import com.google.devtools.build.lib.syntax.SkylarkList.MutableList;
51import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
Carmi Grushko7136f6e2015-11-05 19:26:16 +000052import com.google.devtools.build.lib.testutil.MoreAsserts;
Yun Pengfc610052016-06-20 11:44:06 +000053import com.google.devtools.build.lib.util.OsUtils;
Vladimir Moskva748ba862016-09-20 13:46:11 +000054import java.nio.charset.Charset;
55import java.nio.charset.StandardCharsets;
56import java.util.List;
57import java.util.Map;
58import java.util.regex.Pattern;
Florian Weikertb4c59042015-12-01 10:47:18 +000059import org.junit.Before;
Vladimir Moskva658a8ea2016-09-02 15:39:17 +000060import org.junit.Rule;
Florian Weikertb4c59042015-12-01 10:47:18 +000061import org.junit.Test;
Vladimir Moskva658a8ea2016-09-02 15:39:17 +000062import org.junit.rules.ExpectedException;
Florian Weikertb4c59042015-12-01 10:47:18 +000063import org.junit.runner.RunWith;
64import org.junit.runners.JUnit4;
65
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000066/**
67 * Tests for SkylarkRuleImplementationFunctions.
68 */
Florian Weikertb4c59042015-12-01 10:47:18 +000069@RunWith(JUnit4.class)
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000070public class SkylarkRuleImplementationFunctionsTest extends SkylarkTestCase {
Vladimir Moskva658a8ea2016-09-02 15:39:17 +000071 @Rule public ExpectedException thrown = ExpectedException.none();
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000072
73 @SkylarkSignature(
74 name = "mock",
75 documented = false,
Damien Martin-Guillerez014388c2016-06-14 10:28:31 +000076 parameters = {
77 @Param(name = "mandatory", doc = ""),
78 @Param(name = "optional", doc = "", defaultValue = "None"),
79 @Param(name = "mandatory_key", doc = "", positional = false, named = true),
Yun Pengfc610052016-06-20 11:44:06 +000080 @Param(
81 name = "optional_key",
82 doc = "",
83 defaultValue = "'x'",
84 positional = false,
85 named = true
86 )
87 },
Francois-Rene Rideauab049e02016-02-17 16:13:46 +000088 useEnvironment = true
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000089 )
90 private BuiltinFunction mockFunc;
91
92 /**
93 * Used for {@link #testStackTraceWithoutOriginalMessage()} and {@link
94 * #testNoStackTraceOnInterrupt}.
95 */
96 @SkylarkSignature(name = "throw", documented = false)
97 BuiltinFunction throwFunction;
98
Florian Weikertb4c59042015-12-01 10:47:18 +000099 @Before
Yun Pengfc610052016-06-20 11:44:06 +0000100 public final void createBuildFile() throws Exception {
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000101 scratch.file(
102 "foo/BUILD",
103 "genrule(name = 'foo',",
104 " cmd = 'dummy_cmd',",
105 " srcs = ['a.txt', 'b.img'],",
106 " tools = ['t.exe'],",
107 " outs = ['c.txt'])",
108 "genrule(name = 'bar',",
109 " cmd = 'dummy_cmd',",
110 " srcs = [':jl', ':gl'],",
111 " outs = ['d.txt'])",
112 "genrule(name = 'baz',",
113 " cmd = 'dummy_cmd',",
114 " outs = ['e.txt'])",
115 "java_library(name = 'jl',",
116 " srcs = ['a.java'])",
117 "genrule(name = 'gl',",
118 " cmd = 'touch $(OUTS)',",
119 " srcs = ['a.go'],",
120 " outs = [ 'gl.a', 'gl.gcgox', ],",
121 " output_to_bindir = 1,",
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000122 ")",
123 // The two below are used by testResolveCommand
124 "sh_binary(name = 'mytool',",
125 " srcs = ['mytool.sh'],",
126 " data = ['file1.dat', 'file2.dat'],",
127 ")",
128 "genrule(name = 'resolve_me',",
129 " cmd = 'aa',",
130 " tools = [':mytool', 't.exe'],",
131 " srcs = ['file3.dat', 'file4.dat'],",
132 " outs = ['r1.txt', 'r2.txt'],",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000133 ")");
134 }
135
136 private void setupSkylarkFunction(String line) throws Exception {
137 mockFunc =
138 new BuiltinFunction("mock") {
139 @SuppressWarnings("unused")
140 public Object invoke(
Yun Pengfc610052016-06-20 11:44:06 +0000141 Object mandatory,
142 Object optional,
143 Object mandatoryKey,
144 Object optionalKey,
Francois-Rene Rideauab049e02016-02-17 16:13:46 +0000145 Environment env) {
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000146 return EvalUtils.optionMap(
Francois-Rene Rideauab049e02016-02-17 16:13:46 +0000147 env,
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000148 "mandatory",
149 mandatory,
150 "optional",
151 optional,
152 "mandatory_key",
153 mandatoryKey,
154 "optional_key",
155 optionalKey);
156 }
157 };
lberkiaea56b32017-05-30 12:35:33 +0200158 assertThat(mockFunc.isConfigured()).isFalse();
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000159 mockFunc.configure(
160 SkylarkRuleImplementationFunctionsTest.class
161 .getDeclaredField("mockFunc")
162 .getAnnotation(SkylarkSignature.class));
163 update("mock", mockFunc);
164 eval(line);
165 }
166
167 private void checkSkylarkFunctionError(String errorMsg, String line) throws Exception {
168 try {
169 setupSkylarkFunction(line);
170 fail();
171 } catch (EvalException e) {
172 assertThat(e).hasMessage(errorMsg);
173 }
174 }
175
Florian Weikertb4c59042015-12-01 10:47:18 +0000176 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000177 public void testSkylarkFunctionPosArgs() throws Exception {
178 setupSkylarkFunction("a = mock('a', 'b', mandatory_key='c')");
179 Map<?, ?> params = (Map<?, ?>) lookup("a");
lberkiaea56b32017-05-30 12:35:33 +0200180 assertThat(params.get("mandatory")).isEqualTo("a");
181 assertThat(params.get("optional")).isEqualTo("b");
182 assertThat(params.get("mandatory_key")).isEqualTo("c");
183 assertThat(params.get("optional_key")).isEqualTo("x");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000184 }
185
Florian Weikertb4c59042015-12-01 10:47:18 +0000186 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000187 public void testSkylarkFunctionKwArgs() throws Exception {
188 setupSkylarkFunction("a = mock(optional='b', mandatory='a', mandatory_key='c')");
189 Map<?, ?> params = (Map<?, ?>) lookup("a");
lberkiaea56b32017-05-30 12:35:33 +0200190 assertThat(params.get("mandatory")).isEqualTo("a");
191 assertThat(params.get("optional")).isEqualTo("b");
192 assertThat(params.get("mandatory_key")).isEqualTo("c");
193 assertThat(params.get("optional_key")).isEqualTo("x");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000194 }
195
Florian Weikertb4c59042015-12-01 10:47:18 +0000196 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000197 public void testSkylarkFunctionTooFewArguments() throws Exception {
198 checkSkylarkFunctionError(
199 "insufficient arguments received by mock("
200 + "mandatory, optional = None, *, mandatory_key, optional_key = \"x\") "
201 + "(got 0, expected at least 1)",
202 "mock()");
203 }
204
Florian Weikertb4c59042015-12-01 10:47:18 +0000205 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000206 public void testSkylarkFunctionTooManyArguments() throws Exception {
207 checkSkylarkFunctionError(
208 "too many (3) positional arguments in call to "
209 + "mock(mandatory, optional = None, *, mandatory_key, optional_key = \"x\")",
210 "mock('a', 'b', 'c')");
211 }
212
Florian Weikertb4c59042015-12-01 10:47:18 +0000213 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000214 public void testSkylarkFunctionAmbiguousArguments() throws Exception {
215 checkSkylarkFunctionError(
216 "argument 'mandatory' passed both by position and by name "
217 + "in call to mock(mandatory, optional = None, *, mandatory_key, optional_key = \"x\")",
218 "mock('by position', mandatory='by_key', mandatory_key='c')");
219 }
220
221 @SuppressWarnings("unchecked")
Florian Weikertb4c59042015-12-01 10:47:18 +0000222 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000223 public void testListComprehensionsWithNestedSet() throws Exception {
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000224 Object result = eval("[x + x for x in depset([1, 2, 3])]");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000225 assertThat((Iterable<Object>) result).containsExactly(2, 4, 6).inOrder();
226 }
227
Florian Weikertb4c59042015-12-01 10:47:18 +0000228 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000229 public void testCreateSpawnActionCreatesSpawnAction() throws Exception {
230 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
231 createTestSpawnAction(ruleContext);
Rumou Duan33bab462016-04-25 17:55:12 +0000232 ActionAnalysisMetadata action =
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000233 Iterables.getOnlyElement(
234 ruleContext.getRuleContext().getAnalysisEnvironment().getRegisteredActions());
235 assertThat(action).isInstanceOf(SpawnAction.class);
236 }
237
Florian Weikertb4c59042015-12-01 10:47:18 +0000238 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000239 public void testCreateSpawnActionArgumentsWithCommand() throws Exception {
240 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
241 createTestSpawnAction(ruleContext);
242 SpawnAction action =
243 (SpawnAction)
244 Iterables.getOnlyElement(
245 ruleContext.getRuleContext().getAnalysisEnvironment().getRegisteredActions());
246 assertArtifactFilenames(action.getInputs(), "a.txt", "b.img");
247 assertArtifactFilenames(action.getOutputs(), "a.txt", "b.img");
Yun Pengfc610052016-06-20 11:44:06 +0000248 MoreAsserts.assertContainsSublist(
249 action.getArguments(), "-c", "dummy_command", "", "--a", "--b");
lberkiaea56b32017-05-30 12:35:33 +0200250 assertThat(action.getMnemonic()).isEqualTo("DummyMnemonic");
251 assertThat(action.getProgressMessage()).isEqualTo("dummy_message");
252 assertThat(action.getEnvironment()).isEqualTo(targetConfig.getLocalShellEnvironment());
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000253 }
254
Florian Weikertb4c59042015-12-01 10:47:18 +0000255 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000256 public void testCreateSpawnActionArgumentsWithExecutable() throws Exception {
257 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
258 evalRuleContextCode(
259 ruleContext,
dslomov40ddec32017-07-03 07:15:31 -0400260 "ruleContext.actions.run(",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000261 " inputs = ruleContext.files.srcs,",
262 " outputs = ruleContext.files.srcs,",
263 " arguments = ['--a','--b'],",
264 " executable = ruleContext.files.tools[0])");
265 SpawnAction action =
266 (SpawnAction)
267 Iterables.getOnlyElement(
268 ruleContext.getRuleContext().getAnalysisEnvironment().getRegisteredActions());
269 assertArtifactFilenames(action.getInputs(), "a.txt", "b.img", "t.exe");
270 assertArtifactFilenames(action.getOutputs(), "a.txt", "b.img");
Carmi Grushko7136f6e2015-11-05 19:26:16 +0000271 MoreAsserts.assertContainsSublist(action.getArguments(), "foo/t.exe", "--a", "--b");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000272 }
273
Florian Weikertb4c59042015-12-01 10:47:18 +0000274 @Test
laurentlb4d302732017-06-14 15:57:30 +0200275 public void testCreateActionWithDepsetInput() throws Exception {
276 // Same test as above, with depset as inputs.
277 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
278 evalRuleContextCode(
279 ruleContext,
dslomov40ddec32017-07-03 07:15:31 -0400280 "ruleContext.actions.run(",
laurentlb4d302732017-06-14 15:57:30 +0200281 " inputs = depset(ruleContext.files.srcs),",
282 " outputs = ruleContext.files.srcs,",
283 " arguments = ['--a','--b'],",
284 " executable = ruleContext.files.tools[0])");
285 SpawnAction action =
286 (SpawnAction)
287 Iterables.getOnlyElement(
288 ruleContext.getRuleContext().getAnalysisEnvironment().getRegisteredActions());
289 assertArtifactFilenames(action.getInputs(), "a.txt", "b.img", "t.exe");
290 assertArtifactFilenames(action.getOutputs(), "a.txt", "b.img");
291 MoreAsserts.assertContainsSublist(action.getArguments(), "foo/t.exe", "--a", "--b");
292 }
293
294 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000295 public void testCreateSpawnActionArgumentsBadExecutable() throws Exception {
296 checkErrorContains(
297 createRuleContext("//foo:foo"),
dslomovc7567002017-07-28 22:34:10 +0200298 "expected file or string for executable but got int instead",
dslomov40ddec32017-07-03 07:15:31 -0400299 "ruleContext.actions.run(",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000300 " inputs = ruleContext.files.srcs,",
301 " outputs = ruleContext.files.srcs,",
302 " arguments = ['--a','--b'],",
dslomovc7567002017-07-28 22:34:10 +0200303 " executable = 123)");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000304 }
305
Florian Weikertb4c59042015-12-01 10:47:18 +0000306 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000307 public void testCreateSpawnActionShellCommandList() throws Exception {
308 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
309 evalRuleContextCode(
310 ruleContext,
dslomov40ddec32017-07-03 07:15:31 -0400311 "ruleContext.actions.run_shell(",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000312 " inputs = ruleContext.files.srcs,",
313 " outputs = ruleContext.files.srcs,",
314 " mnemonic = 'DummyMnemonic',",
315 " command = ['dummy_command', '--arg1', '--arg2'],",
316 " progress_message = 'dummy_message')");
317 SpawnAction action =
318 (SpawnAction)
319 Iterables.getOnlyElement(
320 ruleContext.getRuleContext().getAnalysisEnvironment().getRegisteredActions());
321 assertThat(action.getArguments())
322 .containsExactly("dummy_command", "--arg1", "--arg2")
323 .inOrder();
324 }
325
Florian Weikertb4c59042015-12-01 10:47:18 +0000326 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000327 public void testCreateSpawnActionEnvAndExecInfo() throws Exception {
328 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
329 evalRuleContextCode(
330 ruleContext,
331 "env = {'a' : 'b'}",
dslomov40ddec32017-07-03 07:15:31 -0400332 "ruleContext.actions.run_shell(",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000333 " inputs = ruleContext.files.srcs,",
334 " outputs = ruleContext.files.srcs,",
335 " env = env,",
336 " execution_requirements = env,",
337 " mnemonic = 'DummyMnemonic',",
338 " command = 'dummy_command',",
339 " progress_message = 'dummy_message')");
340 SpawnAction action =
341 (SpawnAction)
342 Iterables.getOnlyElement(
343 ruleContext.getRuleContext().getAnalysisEnvironment().getRegisteredActions());
lberkiaea56b32017-05-30 12:35:33 +0200344 assertThat(action.getEnvironment()).containsExactly("a", "b");
345 assertThat(action.getExecutionInfo()).containsExactly("a", "b");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000346 }
347
Florian Weikertb4c59042015-12-01 10:47:18 +0000348 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000349 public void testCreateSpawnActionUnknownParam() throws Exception {
350 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
351 checkErrorContains(
352 ruleContext,
dslomov40ddec32017-07-03 07:15:31 -0400353 "unexpected keyword 'bad_param', in method run("
354 + "list outputs, string bad_param, File executable) of 'actions'",
355 "f = ruleContext.actions.declare_file('foo.sh')",
356 "ruleContext.actions.run(outputs=[], bad_param = 'some text', executable = f)");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000357 }
358
Florian Weikertb4c59042015-12-01 10:47:18 +0000359 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000360 public void testCreateSpawnActionNoExecutable() throws Exception {
361 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
362 checkErrorContains(
363 ruleContext,
364 "You must specify either 'command' or 'executable' argument",
365 "ruleContext.action(outputs=[])");
366 }
367
368 private Object createTestSpawnAction(SkylarkRuleContext ruleContext) throws Exception {
369 return evalRuleContextCode(
370 ruleContext,
dslomov40ddec32017-07-03 07:15:31 -0400371 "ruleContext.actions.run_shell(",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000372 " inputs = ruleContext.files.srcs,",
373 " outputs = ruleContext.files.srcs,",
374 " arguments = ['--a','--b'],",
375 " mnemonic = 'DummyMnemonic',",
376 " command = 'dummy_command',",
377 " progress_message = 'dummy_message',",
378 " use_default_shell_env = True)");
379 }
380
Florian Weikertb4c59042015-12-01 10:47:18 +0000381 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000382 public void testCreateSpawnActionBadGenericArg() throws Exception {
383 checkErrorContains(
384 createRuleContext("//foo:foo"),
Laurent Le Brunc31f3512016-12-29 21:41:33 +0000385 "expected type 'File' for 'outputs' element but got type 'string' instead",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000386 "l = ['a', 'b']",
dslomov40ddec32017-07-03 07:15:31 -0400387 "ruleContext.actions.run_shell(",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000388 " outputs = l,",
389 " command = 'dummy_command')");
390 }
391
Florian Weikertb4c59042015-12-01 10:47:18 +0000392 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000393 public void testCreateSpawnActionCommandsListTooShort() throws Exception {
394 checkErrorContains(
395 createRuleContext("//foo:foo"),
396 "'command' list has to be of size at least 3",
dslomov40ddec32017-07-03 07:15:31 -0400397 "ruleContext.actions.run_shell(",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000398 " outputs = ruleContext.files.srcs,",
399 " command = ['dummy_command', '--arg'])");
400 }
401
Florian Weikertb4c59042015-12-01 10:47:18 +0000402 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000403 public void testCreateFileAction() throws Exception {
404 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
Laurent Le Bruna708b622016-05-11 14:24:39 +0000405 evalRuleContextCode(
406 ruleContext,
dslomov90ccaa52017-06-30 12:21:28 +0200407 "ruleContext.actions.write(",
Laurent Le Bruna708b622016-05-11 14:24:39 +0000408 " output = ruleContext.files.srcs[0],",
409 " content = 'hello world',",
dslomov90ccaa52017-06-30 12:21:28 +0200410 " is_executable = False)");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000411 FileWriteAction action =
412 (FileWriteAction)
Laurent Le Bruna708b622016-05-11 14:24:39 +0000413 Iterables.getOnlyElement(
414 ruleContext.getRuleContext().getAnalysisEnvironment().getRegisteredActions());
lberkiaea56b32017-05-30 12:35:33 +0200415 assertThat(Iterables.getOnlyElement(action.getOutputs()).getExecPathString())
416 .isEqualTo("foo/a.txt");
417 assertThat(action.getFileContents()).isEqualTo("hello world");
418 assertThat(action.makeExecutable()).isFalse();
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000419 }
420
Florian Weikertb4c59042015-12-01 10:47:18 +0000421 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000422 public void testEmptyAction() throws Exception {
423 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
424
425 checkEmptyAction(ruleContext, "mnemonic = 'test'");
426 checkEmptyAction(ruleContext, "mnemonic = 'test', inputs = ruleContext.files.srcs");
laurentlb4cbe5f32017-06-14 16:52:03 +0200427 checkEmptyAction(ruleContext, "mnemonic = 'test', inputs = depset(ruleContext.files.srcs)");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000428
429 checkErrorContains(
430 ruleContext,
dslomovae0b7742017-06-30 10:07:48 +0200431 "parameter 'mnemonic' has no default value, in method do_nothing(list inputs) of 'actions'",
432 "ruleContext.actions.do_nothing(inputs = ruleContext.files.srcs)");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000433 }
434
435 private void checkEmptyAction(SkylarkRuleContext ruleContext, String namedArgs) throws Exception {
436 assertThat(
437 evalRuleContextCode(
dslomovae0b7742017-06-30 10:07:48 +0200438 ruleContext, String.format("ruleContext.actions.do_nothing(%s)", namedArgs)))
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000439 .isEqualTo(Runtime.NONE);
440 }
441
Florian Weikertb4c59042015-12-01 10:47:18 +0000442 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000443 public void testEmptyActionWithExtraAction() throws Exception {
444 scratch.file(
445 "test/empty.bzl",
446 "def _impl(ctx):",
dslomovae0b7742017-06-30 10:07:48 +0200447 " ctx.actions.do_nothing(",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000448 " inputs = ctx.files.srcs,",
449 " mnemonic = 'EA',",
450 " )",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000451 "empty_action_rule = rule(",
452 " implementation = _impl,",
453 " attrs = {",
454 " \"srcs\": attr.label_list(allow_files=True),",
455 " }",
456 ")");
457
458 scratch.file(
459 "test/BUILD",
460 "load('/test/empty', 'empty_action_rule')",
461 "empty_action_rule(name = 'my_empty_action',",
462 " srcs = ['foo.in', 'other_foo.in'])",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000463 "action_listener(name = 'listener',",
464 " mnemonics = ['EA'],",
465 " extra_actions = [':extra'])",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000466 "extra_action(name = 'extra',",
467 " cmd='')");
468
469 getPseudoActionViaExtraAction("//test:my_empty_action", "//test:listener");
470 }
471
Florian Weikertb4c59042015-12-01 10:47:18 +0000472 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000473 public void testExpandLocation() throws Exception {
474 SkylarkRuleContext ruleContext = createRuleContext("//foo:bar");
475
476 // If there is only a single target, both "location" and "locations" should work
477 runExpansion(ruleContext, "location :jl", "[blaze]*-out/.*/bin/foo/libjl.jar");
478 runExpansion(ruleContext, "locations :jl", "[blaze]*-out/.*/bin/foo/libjl.jar");
479
480 runExpansion(ruleContext, "location //foo:jl", "[blaze]*-out/.*/bin/foo/libjl.jar");
481
482 // Multiple targets and "location" should result in an error
483 checkReportedErrorStartsWith(
484 ruleContext,
485 "in genrule rule //foo:bar: label '//foo:gl' "
486 + "in $(location) expression expands to more than one file, please use $(locations "
487 + "//foo:gl) instead.",
488 "ruleContext.expand_location('$(location :gl)')");
489
490 // We have to use "locations" for multiple targets
491 runExpansion(
492 ruleContext,
493 "locations :gl",
494 "[blaze]*-out/.*/bin/foo/gl.a [blaze]*-out/.*/bin/foo/gl.gcgox");
495
496 // LocationExpander just returns the input string if there is no label
497 runExpansion(ruleContext, "location", "\\$\\(location\\)");
498
499 checkReportedErrorStartsWith(
500 ruleContext,
501 "in genrule rule //foo:bar: label '//foo:abc' in $(locations) expression "
502 + "is not a declared prerequisite of this rule",
503 "ruleContext.expand_location('$(locations :abc)')");
504 }
505
506 /**
507 * Invokes ctx.expand_location() with the given parameters and checks whether this led to the
508 * expected result
509 * @param ruleContext The rule context
510 * @param command Either "location" or "locations". This only matters when the label has multiple
511 * targets
512 * @param expectedPattern Regex pattern that matches the expected result
513 */
514 private void runExpansion(SkylarkRuleContext ruleContext, String command, String expectedPattern)
515 throws Exception {
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000516 assertMatches(
517 "Expanded string",
518 expectedPattern,
Yun Pengfc610052016-06-20 11:44:06 +0000519 (String)
520 evalRuleContextCode(
521 ruleContext, String.format("ruleContext.expand_location('$(%s)')", command)));
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000522 }
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000523
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000524 private void assertMatches(String description, String expectedPattern, String computedValue)
525 throws Exception {
lberkiaea56b32017-05-30 12:35:33 +0200526 assertWithMessage(
527 Printer.format(
528 "%s %r did not match pattern '%s'", description, computedValue, expectedPattern))
529 .that(Pattern.matches(expectedPattern, computedValue))
530 .isTrue();
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000531 }
532
Florian Weikertb4c59042015-12-01 10:47:18 +0000533 @Test
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000534 public void testResolveCommandMakeVariables() throws Exception {
535 evalRuleContextCode(
536 createRuleContext("//foo:resolve_me"),
537 "inputs, argv, manifests = ruleContext.resolve_command(",
538 " command='I got the $(HELLO) on a $(DAVE)', ",
539 " make_variables={'HELLO': 'World', 'DAVE': type('')})");
540 @SuppressWarnings("unchecked")
Francois-Rene Rideaua2c9ac62016-01-22 10:54:38 +0000541 List<String> argv = (List<String>) (List<?>) (MutableList) lookup("argv");
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000542 assertThat(argv).hasSize(3);
Yun Pengfc610052016-06-20 11:44:06 +0000543 assertMatches("argv[0]", "^.*/bash" + OsUtils.executableExtension() + "$", argv.get(0));
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000544 assertThat(argv.get(1)).isEqualTo("-c");
545 assertThat(argv.get(2)).isEqualTo("I got the World on a string");
546 }
547
Florian Weikertb4c59042015-12-01 10:47:18 +0000548 @Test
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000549 public void testResolveCommandInputs() throws Exception {
550 evalRuleContextCode(
551 createRuleContext("//foo:resolve_me"),
Michajlo Matijkiw4a877382017-01-27 19:30:34 +0000552 "inputs, argv, input_manifests = ruleContext.resolve_command(",
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000553 " tools=ruleContext.attr.tools)");
554 @SuppressWarnings("unchecked")
Francois-Rene Rideaua2c9ac62016-01-22 10:54:38 +0000555 List<Artifact> inputs = (List<Artifact>) (List<?>) (MutableList) lookup("inputs");
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000556 assertArtifactFilenames(inputs, "mytool.sh", "mytool", "foo_Smytool-runfiles", "t.exe");
Michajlo Matijkiw4a877382017-01-27 19:30:34 +0000557 @SuppressWarnings("unchecked")
558 CompositeRunfilesSupplier runfilesSupplier =
559 new CompositeRunfilesSupplier((List<RunfilesSupplier>) lookup("input_manifests"));
560 assertThat(runfilesSupplier.getMappings()).hasSize(1);
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000561 }
562
Florian Weikertb4c59042015-12-01 10:47:18 +0000563 @Test
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000564 public void testResolveCommandExpandLocations() throws Exception {
565 evalRuleContextCode(
566 createRuleContext("//foo:resolve_me"),
567 "def foo():", // no for loops at top-level
568 " label_dict = {}",
569 " all = []",
570 " for dep in ruleContext.attr.srcs + ruleContext.attr.tools:",
571 " all.extend(list(dep.files))",
572 " label_dict[dep.label] = list(dep.files)",
573 " return ruleContext.resolve_command(",
574 " command='A$(locations //foo:mytool) B$(location //foo:file3.dat)',",
575 " attribute='cmd', expand_locations=True, label_dict=label_dict)",
576 "inputs, argv, manifests = foo()");
577 @SuppressWarnings("unchecked")
Francois-Rene Rideaua2c9ac62016-01-22 10:54:38 +0000578 List<String> argv = (List<String>) (List<?>) (MutableList) lookup("argv");
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000579 assertThat(argv).hasSize(3);
Yun Pengfc610052016-06-20 11:44:06 +0000580 assertMatches("argv[0]", "^.*/bash" + OsUtils.executableExtension() + "$", argv.get(0));
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000581 assertThat(argv.get(1)).isEqualTo("-c");
582 assertMatches("argv[2]", "A.*/mytool .*/mytool.sh B.*file3.dat", argv.get(2));
583 }
Yun Pengfc610052016-06-20 11:44:06 +0000584
Chris Parsons9a9573b2016-02-10 21:15:11 +0000585 @Test
586 public void testResolveCommandExecutionRequirements() throws Exception {
587 // Tests that requires-darwin execution requirements result in the usage of /bin/bash.
588 evalRuleContextCode(
589 createRuleContext("//foo:resolve_me"),
590 "inputs, argv, manifests = ruleContext.resolve_command(",
591 " execution_requirements={'requires-darwin': ''})");
592 @SuppressWarnings("unchecked")
593 List<String> argv = (List<String>) (List<?>) (MutableList) lookup("argv");
594 assertMatches("argv[0]", "^/bin/bash$", argv.get(0));
595 }
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000596
Florian Weikertb4c59042015-12-01 10:47:18 +0000597 @Test
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000598 public void testResolveCommandScript() throws Exception {
599 evalRuleContextCode(
600 createRuleContext("//foo:resolve_me"),
601 "def foo():", // no for loops at top-level
602 " s = 'a'",
603 " for i in range(1,17): s = s + s", // 2**17 > CommandHelper.maxCommandLength (=64000)
604 " return ruleContext.resolve_command(",
605 " command=s)",
606 "argv = foo()[1]");
607 @SuppressWarnings("unchecked")
Francois-Rene Rideaua2c9ac62016-01-22 10:54:38 +0000608 List<String> argv = (List<String>) (List<?>) (MutableList) lookup("argv");
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000609 assertThat(argv).hasSize(2);
Yun Pengfc610052016-06-20 11:44:06 +0000610 assertMatches("argv[0]", "^.*/bash" + OsUtils.executableExtension() + "$", argv.get(0));
Francois-Rene Rideau0f1b51e2015-10-20 17:32:16 +0000611 assertMatches("argv[1]", "^.*/resolve_me[.]script[.]sh$", argv.get(1));
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000612 }
613
Florian Weikertb4c59042015-12-01 10:47:18 +0000614 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000615 public void testBadParamTypeErrorMessage() throws Exception {
616 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
617 checkErrorContains(
618 ruleContext,
dslomov90ccaa52017-06-30 12:21:28 +0200619 "Cannot convert parameter 'content' to type string, in method "
620 + "write(File output, int content, bool is_executable) of 'actions'",
621 "ruleContext.actions.write(",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000622 " output = ruleContext.files.srcs[0],",
623 " content = 1,",
dslomov90ccaa52017-06-30 12:21:28 +0200624 " is_executable = False)");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000625 }
626
Florian Weikertb4c59042015-12-01 10:47:18 +0000627 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000628 public void testCreateTemplateAction() throws Exception {
629 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
dslomov68aafa22017-07-03 09:43:58 -0400630 evalRuleContextCode(
631 ruleContext,
632 "ruleContext.actions.expand_template(",
633 " template = ruleContext.files.srcs[0],",
634 " output = ruleContext.files.srcs[1],",
635 " substitutions = {'a': 'b'},",
laurentlba4bfe162017-07-31 15:53:07 +0200636 " is_executable = False)");
dslomov68aafa22017-07-03 09:43:58 -0400637
638 TemplateExpansionAction action = (TemplateExpansionAction) Iterables.getOnlyElement(
639 ruleContext.getRuleContext().getAnalysisEnvironment().getRegisteredActions());
lberkiaea56b32017-05-30 12:35:33 +0200640 assertThat(Iterables.getOnlyElement(action.getInputs()).getExecPathString())
641 .isEqualTo("foo/a.txt");
642 assertThat(Iterables.getOnlyElement(action.getOutputs()).getExecPathString())
643 .isEqualTo("foo/b.img");
644 assertThat(Iterables.getOnlyElement(action.getSubstitutions()).getKey()).isEqualTo("a");
645 assertThat(Iterables.getOnlyElement(action.getSubstitutions()).getValue()).isEqualTo("b");
646 assertThat(action.makeExecutable()).isFalse();
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000647 }
648
649 /**
650 * Simulates the fact that the Parser currently uses Latin1 to read BUILD files, while users
John Field585d1a02015-12-16 16:03:52 +0000651 * usually write those files using UTF-8 encoding. Currently, the string-valued 'substitutions'
652 * parameter of the template_action function contains a hack that assumes its input is a UTF-8
653 * encoded string which has been ingested as Latin 1. The hack converts the string to its
654 * "correct" UTF-8 value. Once {@link com.google.devtools.build.lib.syntax.ParserInputSource#create(com.google.devtools.build.lib.vfs.Path)}
655 * parses files using UTF-8 and the hack for the substituations parameter is removed, this test
656 * will fail.
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000657 */
Florian Weikertb4c59042015-12-01 10:47:18 +0000658 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000659 public void testCreateTemplateActionWithWrongEncoding() throws Exception {
John Field585d1a02015-12-16 16:03:52 +0000660 // The following array contains bytes that represent a string of length two when treated as
661 // UTF-8 and a string of length four when treated as ISO-8859-1 (a.k.a. Latin 1).
662 byte[] bytesToDecode = {(byte) 0xC2, (byte) 0xA2, (byte) 0xC2, (byte) 0xA2};
663 Charset latin1 = StandardCharsets.ISO_8859_1;
664 Charset utf8 = StandardCharsets.UTF_8;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000665 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
dslomov68aafa22017-07-03 09:43:58 -0400666 evalRuleContextCode(
667 ruleContext,
668 "ruleContext.actions.expand_template(",
669 " template = ruleContext.files.srcs[0],",
670 " output = ruleContext.files.srcs[1],",
671 " substitutions = {'a': '" + new String(bytesToDecode, latin1) + "'},",
laurentlba4bfe162017-07-31 15:53:07 +0200672 " is_executable = False)");
dslomov68aafa22017-07-03 09:43:58 -0400673 TemplateExpansionAction action = (TemplateExpansionAction) Iterables.getOnlyElement(
674 ruleContext.getRuleContext().getAnalysisEnvironment().getRegisteredActions());
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000675 List<Substitution> substitutions = action.getSubstitutions();
676 assertThat(substitutions).hasSize(1);
John Field585d1a02015-12-16 16:03:52 +0000677 assertThat(substitutions.get(0).getValue()).isEqualTo(new String(bytesToDecode, utf8));
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000678 }
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000679
Florian Weikertb4c59042015-12-01 10:47:18 +0000680 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000681 public void testRunfilesAddFromDependencies() throws Exception {
682 SkylarkRuleContext ruleContext = createRuleContext("//foo:bar");
683 Object result =
684 evalRuleContextCode(ruleContext, "ruleContext.runfiles(collect_default = True)");
685 assertThat(ActionsTestUtil.baseArtifactNames(getRunfileArtifacts(result)))
686 .contains("libjl.jar");
687 }
688
Florian Weikertb4c59042015-12-01 10:47:18 +0000689 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000690 public void testRunfilesBadListGenericType() throws Exception {
691 checkErrorContains(
Laurent Le Brunc31f3512016-12-29 21:41:33 +0000692 "expected type 'File' for 'files' element but got type 'string' instead",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000693 "ruleContext.runfiles(files = ['some string'])");
694 }
695
Florian Weikertb4c59042015-12-01 10:47:18 +0000696 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000697 public void testRunfilesBadSetGenericType() throws Exception {
698 checkErrorContains(
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000699 "expected depset of Files or NoneType for 'transitive_files' while calling runfiles "
Vladimir Moskvaba4f0bb2017-01-30 15:45:49 +0000700 + "but got depset of ints instead: depset([1, 2, 3])",
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000701 "ruleContext.runfiles(transitive_files=depset([1, 2, 3]))");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000702 }
703
Florian Weikertb4c59042015-12-01 10:47:18 +0000704 @Test
Googlerc85af312016-03-10 17:55:17 +0000705 public void testRunfilesBadMapGenericType() throws Exception {
706 checkErrorContains(
vladmos7f6d3a12017-07-17 23:15:21 +0200707 "expected type 'string' for 'symlinks' key but got type 'int' instead",
Googlerc85af312016-03-10 17:55:17 +0000708 "ruleContext.runfiles(symlinks = {123: ruleContext.files.srcs[0]})");
709 checkErrorContains(
vladmos7f6d3a12017-07-17 23:15:21 +0200710 "expected type 'File' for 'symlinks' value but got type 'int' instead",
Googlerc85af312016-03-10 17:55:17 +0000711 "ruleContext.runfiles(symlinks = {'some string': 123})");
712 checkErrorContains(
vladmos7f6d3a12017-07-17 23:15:21 +0200713 "expected type 'string' for 'root_symlinks' key but got type 'int' instead",
Googlerc85af312016-03-10 17:55:17 +0000714 "ruleContext.runfiles(root_symlinks = {123: ruleContext.files.srcs[0]})");
715 checkErrorContains(
vladmos7f6d3a12017-07-17 23:15:21 +0200716 "expected type 'File' for 'root_symlinks' value but got type 'int' instead",
Googlerc85af312016-03-10 17:55:17 +0000717 "ruleContext.runfiles(root_symlinks = {'some string': 123})");
718 }
719
720 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000721 public void testRunfilesArtifactsFromArtifact() throws Exception {
722 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
723 Object result =
724 evalRuleContextCode(
725 ruleContext,
726 "artifacts = ruleContext.files.tools",
727 "ruleContext.runfiles(files = artifacts)");
728 assertThat(ActionsTestUtil.baseArtifactNames(getRunfileArtifacts(result))).contains("t.exe");
729 }
730
Florian Weikertb4c59042015-12-01 10:47:18 +0000731 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000732 public void testRunfilesArtifactsFromIterableArtifacts() throws Exception {
733 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
734 Object result =
735 evalRuleContextCode(
736 ruleContext,
737 "artifacts = ruleContext.files.srcs",
738 "ruleContext.runfiles(files = artifacts)");
lberkiaea56b32017-05-30 12:35:33 +0200739 assertThat(ImmutableList.of("a.txt", "b.img"))
740 .isEqualTo(ActionsTestUtil.baseArtifactNames(getRunfileArtifacts(result)));
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000741 }
742
Florian Weikertb4c59042015-12-01 10:47:18 +0000743 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000744 public void testRunfilesArtifactsFromNestedSetArtifacts() throws Exception {
745 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
746 Object result =
747 evalRuleContextCode(
748 ruleContext,
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000749 "ftb = depset() + ruleContext.files.srcs",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000750 "ruleContext.runfiles(transitive_files = ftb)");
lberkiaea56b32017-05-30 12:35:33 +0200751 assertThat(ImmutableList.of("a.txt", "b.img"))
752 .isEqualTo(ActionsTestUtil.baseArtifactNames(getRunfileArtifacts(result)));
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000753 }
754
Florian Weikertb4c59042015-12-01 10:47:18 +0000755 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000756 public void testRunfilesArtifactsFromDefaultAndFiles() throws Exception {
757 SkylarkRuleContext ruleContext = createRuleContext("//foo:bar");
758 Object result =
759 evalRuleContextCode(
760 ruleContext,
761 "artifacts = ruleContext.files.srcs",
762 // It would be nice to write [DEFAULT] + artifacts, but artifacts
763 // is an ImmutableList and Skylark interprets it as a tuple.
764 "ruleContext.runfiles(collect_default = True, files = artifacts)");
765 // From DEFAULT only libjl.jar comes, see testRunfilesAddFromDependencies().
lberkiaea56b32017-05-30 12:35:33 +0200766 assertThat(ImmutableList.of("libjl.jar", "gl.a", "gl.gcgox"))
767 .isEqualTo(ActionsTestUtil.baseArtifactNames(getRunfileArtifacts(result)));
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000768 }
769
Googlerc85af312016-03-10 17:55:17 +0000770 @Test
771 public void testRunfilesArtifactsFromSymlink() throws Exception {
772 Object result =
773 evalRuleContextCode(
774 "artifacts = ruleContext.files.srcs",
775 "ruleContext.runfiles(symlinks = {'sym1': artifacts[0]})");
lberkiaea56b32017-05-30 12:35:33 +0200776 assertThat(ImmutableList.of("a.txt"))
777 .isEqualTo(ActionsTestUtil.baseArtifactNames(getRunfileArtifacts(result)));
Googlerc85af312016-03-10 17:55:17 +0000778 }
779
780 @Test
781 public void testRunfilesArtifactsFromRootSymlink() throws Exception {
782 Object result =
783 evalRuleContextCode(
784 "artifacts = ruleContext.files.srcs",
785 "ruleContext.runfiles(root_symlinks = {'sym1': artifacts[0]})");
lberkiaea56b32017-05-30 12:35:33 +0200786 assertThat(ImmutableList.of("a.txt"))
787 .isEqualTo(ActionsTestUtil.baseArtifactNames(getRunfileArtifacts(result)));
Googlerc85af312016-03-10 17:55:17 +0000788 }
789
790 @Test
791 public void testRunfilesSymlinkConflict() throws Exception {
792 // Two different artifacts mapped to same path in runfiles
793 Object result =
794 evalRuleContextCode(
795 "artifacts = ruleContext.files.srcs",
796 "prefix = ruleContext.workspace_name + '/' if ruleContext.workspace_name else ''",
797 "ruleContext.runfiles(",
798 "root_symlinks = {prefix + 'sym1': artifacts[0]},",
799 "symlinks = {'sym1': artifacts[1]})");
800 Runfiles runfiles = (Runfiles) result;
801 reporter.removeHandler(failFastHandler); // So it doesn't throw exception
802 runfiles.getRunfilesInputs(reporter, null);
803 assertContainsEvent("ERROR <no location>: overwrote runfile");
804 }
805
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000806 private Iterable<Artifact> getRunfileArtifacts(Object runfiles) {
807 return ((Runfiles) runfiles).getAllArtifacts();
808 }
809
Florian Weikertb4c59042015-12-01 10:47:18 +0000810 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000811 public void testRunfilesBadKeywordArguments() throws Exception {
812 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
813 checkErrorContains(
814 ruleContext,
815 "unexpected keyword 'bad_keyword' in call to runfiles(self: ctx, ",
816 "ruleContext.runfiles(bad_keyword = '')");
817 }
818
Florian Weikertb4c59042015-12-01 10:47:18 +0000819 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000820 public void testNsetContainsList() throws Exception {
821 checkErrorContains(
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000822 "depsets cannot contain items of type 'list'", "depset() + [ruleContext.files.srcs]");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000823 }
824
Florian Weikertb4c59042015-12-01 10:47:18 +0000825 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000826 public void testCmdJoinPaths() throws Exception {
827 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
828 Object result =
829 evalRuleContextCode(
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000830 ruleContext, "f = depset(ruleContext.files.srcs)", "cmd_helper.join_paths(':', f)");
lberkiaea56b32017-05-30 12:35:33 +0200831 assertThat(result).isEqualTo("foo/a.txt:foo/b.img");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000832 }
833
Florian Weikertb4c59042015-12-01 10:47:18 +0000834 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000835 public void testStructPlusArtifactErrorMessage() throws Exception {
836 SkylarkRuleContext ruleContext = createRuleContext("//foo:foo");
837 checkErrorContains(
838 ruleContext,
839 "unsupported operand type(s) for +: 'File' and 'struct'",
840 "ruleContext.files.tools[0] + struct(a = 1)");
841 }
842
Florian Weikertb4c59042015-12-01 10:47:18 +0000843 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000844 public void testNoSuchProviderErrorMessage() throws Exception {
845 checkErrorContains(
846 createRuleContext("//foo:bar"),
vladmos7f6d3a12017-07-17 23:15:21 +0200847 "<target //foo:jl> (rule 'java_library') doesn't have provider 'my_provider'",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000848 "ruleContext.attr.srcs[0].my_provider");
849 }
850
Florian Weikertb4c59042015-12-01 10:47:18 +0000851 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000852 public void testFilesForRuleConfiguredTarget() throws Exception {
853 Object result =
854 evalRuleContextCode(createRuleContext("//foo:foo"), "ruleContext.attr.srcs[0].files");
lberkiaea56b32017-05-30 12:35:33 +0200855 assertThat(ActionsTestUtil.baseNamesOf(((SkylarkNestedSet) result).getSet(Artifact.class)))
856 .isEqualTo("a.txt");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000857 }
858
Florian Weikertb4c59042015-12-01 10:47:18 +0000859 @Test
Vladimir Moskvaeb0cfc52016-11-09 12:54:51 +0000860 public void testDefaultProvider() throws Exception {
861 scratch.file(
862 "test/foo.bzl",
863 "foo_provider = provider()",
864 "def _impl(ctx):",
dslomov3aa7d2f2017-04-11 17:55:55 +0000865 " default = DefaultInfo(",
Vladimir Moskvaeb0cfc52016-11-09 12:54:51 +0000866 " runfiles=ctx.runfiles(ctx.files.runs),",
867 " )",
868 " foo = foo_provider()",
869 " return [foo, default]",
870 "foo_rule = rule(",
871 " implementation = _impl,",
872 " attrs = {",
873 " 'runs': attr.label_list(allow_files=True),",
874 " }",
875 ")"
876 );
877 scratch.file(
878 "test/bar.bzl",
879 "load(':foo.bzl', 'foo_provider')",
880 "def _impl(ctx):",
dslomov3aa7d2f2017-04-11 17:55:55 +0000881 " provider = ctx.attr.deps[0][DefaultInfo]",
vladmos360fb4d2017-04-11 11:14:22 +0000882 " return struct(",
vladmos1341e3e2017-04-14 16:34:15 +0200883 " is_provided = DefaultInfo in ctx.attr.deps[0],",
vladmos360fb4d2017-04-11 11:14:22 +0000884 " provider = provider,",
885 " dir = str(sorted(dir(provider))),",
886 " rule_data_runfiles = provider.data_runfiles,",
887 " rule_default_runfiles = provider.default_runfiles,",
888 " rule_files = provider.files,",
889 " rule_files_to_run = provider.files_to_run,",
Vladimir Moskvaeb0cfc52016-11-09 12:54:51 +0000890 " )",
891 "bar_rule = rule(",
892 " implementation = _impl,",
893 " attrs = {",
894 " 'deps': attr.label_list(allow_files=True),",
895 " }",
vladmos360fb4d2017-04-11 11:14:22 +0000896 ")");
Vladimir Moskvaeb0cfc52016-11-09 12:54:51 +0000897 scratch.file(
898 "test/BUILD",
899 "load(':foo.bzl', 'foo_rule')",
900 "load(':bar.bzl', 'bar_rule')",
901 "foo_rule(name = 'dep_rule', runs = ['run.file', 'run2.file'])",
vladmos360fb4d2017-04-11 11:14:22 +0000902 "bar_rule(name = 'my_rule', deps = [':dep_rule', 'file.txt'])");
Vladimir Moskvaeb0cfc52016-11-09 12:54:51 +0000903 ConfiguredTarget configuredTarget = getConfiguredTarget("//test:my_rule");
vladmos360fb4d2017-04-11 11:14:22 +0000904
dslomov211a3ba2017-05-16 00:21:22 +0200905 assertThat((Boolean) configuredTarget.get("is_provided")).isTrue();
vladmos1341e3e2017-04-14 16:34:15 +0200906
dslomov211a3ba2017-05-16 00:21:22 +0200907 Object provider = configuredTarget.get("provider");
vladmos360fb4d2017-04-11 11:14:22 +0000908 assertThat(provider).isInstanceOf(DefaultProvider.class);
vladmos97d67082017-07-13 14:54:03 +0200909 assertThat(((SkylarkClassObject) provider).getConstructor().getKey()).isEqualTo(
910 DefaultProvider.SKYLARK_CONSTRUCTOR.getKey());
Vladimir Moskvaeb0cfc52016-11-09 12:54:51 +0000911
dslomov211a3ba2017-05-16 00:21:22 +0200912 assertThat(configuredTarget.get("dir"))
vladmos360fb4d2017-04-11 11:14:22 +0000913 .isEqualTo(
914 "[\"data_runfiles\", \"default_runfiles\", \"files\", \"files_to_run\", \"to_json\", "
915 + "\"to_proto\"]");
916
dslomov211a3ba2017-05-16 00:21:22 +0200917 assertThat(configuredTarget.get("rule_data_runfiles")).isInstanceOf(Runfiles.class);
vladmos360fb4d2017-04-11 11:14:22 +0000918 assertThat(
919 Iterables.transform(
dslomov211a3ba2017-05-16 00:21:22 +0200920 ((Runfiles) configuredTarget.get("rule_data_runfiles")).getAllArtifacts(),
laurentlb59800122017-07-03 11:42:25 -0400921 String::valueOf))
vladmos360fb4d2017-04-11 11:14:22 +0000922 .containsExactly(
923 "File:[/workspace[source]]test/run.file", "File:[/workspace[source]]test/run2.file");
924
dslomov211a3ba2017-05-16 00:21:22 +0200925 assertThat(configuredTarget.get("rule_default_runfiles")).isInstanceOf(Runfiles.class);
926 assertThat(
927 Iterables.transform(
928 ((Runfiles) configuredTarget.get("rule_default_runfiles")).getAllArtifacts(),
laurentlb59800122017-07-03 11:42:25 -0400929 String::valueOf))
dslomov211a3ba2017-05-16 00:21:22 +0200930 .containsExactly(
931 "File:[/workspace[source]]test/run.file", "File:[/workspace[source]]test/run2.file");
932
933 assertThat(configuredTarget.get("rule_files")).isInstanceOf(SkylarkNestedSet.class);
934 assertThat(configuredTarget.get("rule_files_to_run")).isInstanceOf(FilesToRunProvider.class);
vladmos360fb4d2017-04-11 11:14:22 +0000935 }
936
937 @Test
vladmos97d67082017-07-13 14:54:03 +0200938 public void testDefaultProviderInStruct() throws Exception {
939 scratch.file(
940 "test/foo.bzl",
941 "foo_provider = provider()",
942 "def _impl(ctx):",
943 " default = DefaultInfo(",
944 " runfiles=ctx.runfiles(ctx.files.runs),",
945 " )",
946 " foo = foo_provider()",
947 " return struct(providers=[foo, default])",
948 "foo_rule = rule(",
949 " implementation = _impl,",
950 " attrs = {",
951 " 'runs': attr.label_list(allow_files=True),",
952 " }",
953 ")");
954 scratch.file(
955 "test/bar.bzl",
956 "load(':foo.bzl', 'foo_provider')",
957 "def _impl(ctx):",
958 " provider = ctx.attr.deps[0][DefaultInfo]",
959 " return struct(",
960 " is_provided = DefaultInfo in ctx.attr.deps[0],",
961 " provider = provider,",
962 " dir = str(sorted(dir(provider))),",
963 " rule_data_runfiles = provider.data_runfiles,",
964 " rule_default_runfiles = provider.default_runfiles,",
965 " rule_files = provider.files,",
966 " rule_files_to_run = provider.files_to_run,",
967 " )",
968 "bar_rule = rule(",
969 " implementation = _impl,",
970 " attrs = {",
971 " 'deps': attr.label_list(allow_files=True),",
972 " }",
973 ")");
974 scratch.file(
975 "test/BUILD",
976 "load(':foo.bzl', 'foo_rule')",
977 "load(':bar.bzl', 'bar_rule')",
978 "foo_rule(name = 'dep_rule', runs = ['run.file', 'run2.file'])",
979 "bar_rule(name = 'my_rule', deps = [':dep_rule', 'file.txt'])");
980 ConfiguredTarget configuredTarget = getConfiguredTarget("//test:my_rule");
981
982 assertThat((Boolean) configuredTarget.get("is_provided")).isTrue();
983
984 Object provider = configuredTarget.get("provider");
985 assertThat(provider).isInstanceOf(DefaultProvider.class);
986 assertThat(((SkylarkClassObject) provider).getConstructor().getKey()).isEqualTo(
987 DefaultProvider.SKYLARK_CONSTRUCTOR.getKey());
988
989 assertThat(configuredTarget.get("dir"))
990 .isEqualTo(
991 "[\"data_runfiles\", \"default_runfiles\", \"files\", \"files_to_run\", \"to_json\", "
992 + "\"to_proto\"]");
993
994 assertThat(configuredTarget.get("rule_data_runfiles")).isInstanceOf(Runfiles.class);
995 assertThat(
996 Iterables.transform(
997 ((Runfiles) configuredTarget.get("rule_data_runfiles")).getAllArtifacts(),
998 String::valueOf))
999 .containsExactly(
1000 "File:[/workspace[source]]test/run.file", "File:[/workspace[source]]test/run2.file");
1001
1002 assertThat(configuredTarget.get("rule_default_runfiles")).isInstanceOf(Runfiles.class);
1003 assertThat(
1004 Iterables.transform(
1005 ((Runfiles) configuredTarget.get("rule_default_runfiles")).getAllArtifacts(),
1006 String::valueOf))
1007 .containsExactly(
1008 "File:[/workspace[source]]test/run.file", "File:[/workspace[source]]test/run2.file");
1009
1010 assertThat(configuredTarget.get("rule_files")).isInstanceOf(SkylarkNestedSet.class);
1011 assertThat(configuredTarget.get("rule_files_to_run")).isInstanceOf(FilesToRunProvider.class);
1012 }
1013
1014 @Test
1015 public void testDefaultProviderInvalidConfiguration() throws Exception {
1016 scratch.file(
1017 "test/foo.bzl",
1018 "foo_provider = provider()",
1019 "def _impl(ctx):",
1020 " default = DefaultInfo(",
1021 " runfiles=ctx.runfiles(ctx.files.runs),",
1022 " )",
1023 " foo = foo_provider()",
1024 " return struct(providers=[foo, default], files=depset([]))",
1025 "foo_rule = rule(",
1026 " implementation = _impl,",
1027 " attrs = {",
1028 " 'runs': attr.label_list(allow_files=True),",
1029 " }",
1030 ")");
1031 scratch.file(
1032 "test/BUILD",
1033 "load(':foo.bzl', 'foo_rule')",
1034 "foo_rule(name = 'my_rule', runs = ['run.file', 'run2.file'])");
1035
1036 try {
1037 getConfiguredTarget("//test:my_rule");
1038 fail();
1039 } catch (AssertionError expected) {
1040 assertThat(expected)
1041 .hasMessageThat()
1042 .contains(
1043 "Provider 'files' should be specified in DefaultInfo "
1044 + "if it's provided explicitly.");
1045 }
1046 }
1047
1048 @Test
vladmos360fb4d2017-04-11 11:14:22 +00001049 public void testDefaultProviderOnFileTarget() throws Exception {
1050 scratch.file(
1051 "test/bar.bzl",
1052 "def _impl(ctx):",
dslomov3aa7d2f2017-04-11 17:55:55 +00001053 " provider = ctx.attr.deps[0][DefaultInfo]",
vladmos360fb4d2017-04-11 11:14:22 +00001054 " return struct(",
vladmos1341e3e2017-04-14 16:34:15 +02001055 " is_provided = DefaultInfo in ctx.attr.deps[0],",
vladmos360fb4d2017-04-11 11:14:22 +00001056 " provider = provider,",
1057 " dir = str(sorted(dir(provider))),",
1058 " file_data_runfiles = provider.data_runfiles,",
1059 " file_default_runfiles = provider.default_runfiles,",
1060 " file_files = provider.files,",
1061 " file_files_to_run = provider.files_to_run,",
1062 " )",
1063 "bar_rule = rule(",
1064 " implementation = _impl,",
1065 " attrs = {",
1066 " 'deps': attr.label_list(allow_files=True),",
1067 " }",
1068 ")");
1069 scratch.file(
1070 "test/BUILD",
1071 "load(':bar.bzl', 'bar_rule')",
1072 "bar_rule(name = 'my_rule', deps = ['file.txt'])");
1073 ConfiguredTarget configuredTarget = getConfiguredTarget("//test:my_rule");
vladmos360fb4d2017-04-11 11:14:22 +00001074
dslomov211a3ba2017-05-16 00:21:22 +02001075 assertThat((Boolean) configuredTarget.get("is_provided")).isTrue();
vladmos1341e3e2017-04-14 16:34:15 +02001076
dslomov211a3ba2017-05-16 00:21:22 +02001077 Object provider = configuredTarget.get("provider");
vladmos360fb4d2017-04-11 11:14:22 +00001078 assertThat(provider).isInstanceOf(DefaultProvider.class);
vladmos97d67082017-07-13 14:54:03 +02001079 assertThat(((SkylarkClassObject) provider).getConstructor().getKey()).isEqualTo(
1080 DefaultProvider.SKYLARK_CONSTRUCTOR.getKey());
vladmos360fb4d2017-04-11 11:14:22 +00001081
dslomov211a3ba2017-05-16 00:21:22 +02001082 assertThat(configuredTarget.get("dir"))
vladmos360fb4d2017-04-11 11:14:22 +00001083 .isEqualTo(
1084 "[\"data_runfiles\", \"default_runfiles\", \"files\", \"files_to_run\", \"to_json\", "
1085 + "\"to_proto\"]");
1086
dslomov211a3ba2017-05-16 00:21:22 +02001087 assertThat(configuredTarget.get("file_data_runfiles")).isInstanceOf(Runfiles.class);
vladmos360fb4d2017-04-11 11:14:22 +00001088 assertThat(
1089 Iterables.transform(
dslomov211a3ba2017-05-16 00:21:22 +02001090 ((Runfiles) configuredTarget.get("file_data_runfiles")).getAllArtifacts(),
laurentlb59800122017-07-03 11:42:25 -04001091 String::valueOf))
vladmos360fb4d2017-04-11 11:14:22 +00001092 .isEmpty();
1093
dslomov211a3ba2017-05-16 00:21:22 +02001094 assertThat(configuredTarget.get("file_default_runfiles")).isInstanceOf(Runfiles.class);
1095 assertThat(
1096 Iterables.transform(
1097 ((Runfiles) configuredTarget.get("file_default_runfiles")).getAllArtifacts(),
laurentlb59800122017-07-03 11:42:25 -04001098 String::valueOf))
dslomov211a3ba2017-05-16 00:21:22 +02001099 .isEmpty();
1100
1101 assertThat(configuredTarget.get("file_files")).isInstanceOf(SkylarkNestedSet.class);
1102 assertThat(configuredTarget.get("file_files_to_run")).isInstanceOf(FilesToRunProvider.class);
Vladimir Moskvaeb0cfc52016-11-09 12:54:51 +00001103 }
1104
1105 @Test
1106 public void testDefaultProviderProvidedImplicitly() throws Exception {
1107 scratch.file(
1108 "test/foo.bzl",
1109 "foo_provider = provider()",
1110 "def _impl(ctx):",
1111 " foo = foo_provider()",
1112 " return [foo]",
1113 "foo_rule = rule(",
1114 " implementation = _impl,",
1115 ")"
1116 );
1117 scratch.file(
1118 "test/bar.bzl",
1119 "load(':foo.bzl', 'foo_provider')",
1120 "def _impl(ctx):",
1121 " dep = ctx.attr.deps[0]",
dslomov3aa7d2f2017-04-11 17:55:55 +00001122 " provider = dep[DefaultInfo]", // The goal is to test this object
1123 " return struct(", // so we return it here
Vladimir Moskvaeb0cfc52016-11-09 12:54:51 +00001124 " default = provider,",
1125 " )",
1126 "bar_rule = rule(",
1127 " implementation = _impl,",
1128 " attrs = {",
1129 " 'deps': attr.label_list(allow_files=True),",
1130 " }",
1131 ")"
1132 );
1133 scratch.file(
1134 "test/BUILD",
1135 "load(':foo.bzl', 'foo_rule')",
1136 "load(':bar.bzl', 'bar_rule')",
1137 "foo_rule(name = 'dep_rule')",
1138 "bar_rule(name = 'my_rule', deps = [':dep_rule'])");
1139 ConfiguredTarget configuredTarget = getConfiguredTarget("//test:my_rule");
dslomov211a3ba2017-05-16 00:21:22 +02001140 Object provider = configuredTarget.get("default");
vladmos360fb4d2017-04-11 11:14:22 +00001141 assertThat(provider).isInstanceOf(DefaultProvider.class);
vladmos97d67082017-07-13 14:54:03 +02001142 assertThat(((SkylarkClassObject) provider).getConstructor().getKey()).isEqualTo(
1143 DefaultProvider.SKYLARK_CONSTRUCTOR.getKey());
Vladimir Moskvaeb0cfc52016-11-09 12:54:51 +00001144 }
1145
1146 @Test
1147 public void testDefaultProviderUnknownFields() throws Exception {
1148 scratch.file(
1149 "test/foo.bzl",
1150 "foo_provider = provider()",
1151 "def _impl(ctx):",
dslomov3aa7d2f2017-04-11 17:55:55 +00001152 " default = DefaultInfo(",
Vladimir Moskvaeb0cfc52016-11-09 12:54:51 +00001153 " foo=ctx.runfiles(),",
1154 " )",
1155 " return [default]",
1156 "foo_rule = rule(",
1157 " implementation = _impl,",
1158 ")"
1159 );
1160 scratch.file(
1161 "test/BUILD",
1162 "load(':foo.bzl', 'foo_rule')",
1163 "foo_rule(name = 'my_rule')"
1164 );
1165 try {
1166 getConfiguredTarget("//test:my_rule");
1167 fail();
1168 } catch (AssertionError expected) {
lberkiaea56b32017-05-30 12:35:33 +02001169 assertThat(expected).hasMessageThat().contains("Invalid key for default provider: foo");
Vladimir Moskvaeb0cfc52016-11-09 12:54:51 +00001170 }
1171 }
1172
1173 @Test
Vladimir Moskva748ba862016-09-20 13:46:11 +00001174 public void testDeclaredProviders() throws Exception {
1175 scratch.file(
1176 "test/foo.bzl",
1177 "foo_provider = provider()",
1178 "foobar_provider = provider()",
1179 "def _impl(ctx):",
1180 " foo = foo_provider()",
1181 " foobar = foobar_provider()",
1182 " return [foo, foobar]",
1183 "foo_rule = rule(",
1184 " implementation = _impl,",
1185 " attrs = {",
1186 " \"srcs\": attr.label_list(allow_files=True),",
1187 " }",
1188 ")"
1189 );
1190 scratch.file(
1191 "test/bar.bzl",
1192 "load(':foo.bzl', 'foo_provider')",
1193 "def _impl(ctx):",
1194 " dep = ctx.attr.deps[0]",
1195 " provider = dep[foo_provider]", // The goal is to test this object
1196 " return struct(proxy = provider)", // so we return it here
1197 "bar_rule = rule(",
1198 " implementation = _impl,",
1199 " attrs = {",
1200 " 'srcs': attr.label_list(allow_files=True),",
1201 " 'deps': attr.label_list(allow_files=True),",
1202 " }",
1203 ")"
1204 );
1205 scratch.file(
1206 "test/BUILD",
1207 "load(':foo.bzl', 'foo_rule')",
1208 "load(':bar.bzl', 'bar_rule')",
1209 "foo_rule(name = 'dep_rule')",
1210 "bar_rule(name = 'my_rule', deps = [':dep_rule'])");
1211 ConfiguredTarget configuredTarget = getConfiguredTarget("//test:my_rule");
dslomov211a3ba2017-05-16 00:21:22 +02001212 Object provider = configuredTarget.get("proxy");
Vladimir Moskva748ba862016-09-20 13:46:11 +00001213 assertThat(provider).isInstanceOf(SkylarkClassObject.class);
vladmos97d67082017-07-13 14:54:03 +02001214 assertThat(((SkylarkClassObject) provider).getConstructor().getKey()).isEqualTo(
1215 new SkylarkKey(Label.parseAbsolute("//test:foo.bzl"), "foo_provider"));
1216 }
1217
1218 @Test
1219 public void testSingleDeclaredProvider() throws Exception {
1220 scratch.file(
1221 "test/foo.bzl",
1222 "foo_provider = provider()",
1223 "def _impl(ctx):",
1224 " return foo_provider(a=123)",
1225 "foo_rule = rule(",
1226 " implementation = _impl,",
1227 " attrs = {",
1228 " \"srcs\": attr.label_list(allow_files=True),",
1229 " }",
1230 ")");
1231 scratch.file(
1232 "test/bar.bzl",
1233 "load(':foo.bzl', 'foo_provider')",
1234 "def _impl(ctx):",
1235 " dep = ctx.attr.deps[0]",
1236 " provider = dep[foo_provider]", // The goal is to test this object
1237 " return struct(proxy = provider)", // so we return it here
1238 "bar_rule = rule(",
1239 " implementation = _impl,",
1240 " attrs = {",
1241 " 'srcs': attr.label_list(allow_files=True),",
1242 " 'deps': attr.label_list(allow_files=True),",
1243 " }",
1244 ")");
1245 scratch.file(
1246 "test/BUILD",
1247 "load(':foo.bzl', 'foo_rule')",
1248 "load(':bar.bzl', 'bar_rule')",
1249 "foo_rule(name = 'dep_rule')",
1250 "bar_rule(name = 'my_rule', deps = [':dep_rule'])");
1251 ConfiguredTarget configuredTarget = getConfiguredTarget("//test:my_rule");
1252 Object provider = configuredTarget.get("proxy");
1253 assertThat(provider).isInstanceOf(SkylarkClassObject.class);
1254 assertThat(((SkylarkClassObject) provider).getConstructor().getKey()).isEqualTo(
1255 new SkylarkKey(Label.parseAbsolute("//test:foo.bzl"), "foo_provider"));
1256 assertThat(((SkylarkClassObject) provider).getValue("a")).isEqualTo(123);
Vladimir Moskva748ba862016-09-20 13:46:11 +00001257 }
1258
1259 @Test
1260 public void testDeclaredProvidersAliasTarget() throws Exception {
1261 scratch.file(
1262 "test/foo.bzl",
1263 "foo_provider = provider()",
1264 "foobar_provider = provider()",
1265 "def _impl(ctx):",
1266 " foo = foo_provider()",
1267 " foobar = foobar_provider()",
1268 " return [foo, foobar]",
1269 "foo_rule = rule(",
1270 " implementation = _impl,",
1271 " attrs = {",
1272 " \"srcs\": attr.label_list(allow_files=True),",
1273 " }",
1274 ")"
1275 );
1276 scratch.file(
1277 "test/bar.bzl",
1278 "load(':foo.bzl', 'foo_provider')",
1279 "def _impl(ctx):",
1280 " dep = ctx.attr.deps[0]",
1281 " provider = dep[foo_provider]", // The goal is to test this object
1282 " return struct(proxy = provider)", // so we return it here
1283 "bar_rule = rule(",
1284 " implementation = _impl,",
1285 " attrs = {",
1286 " 'srcs': attr.label_list(allow_files=True),",
1287 " 'deps': attr.label_list(allow_files=True),",
1288 " }",
1289 ")"
1290 );
1291 scratch.file(
1292 "test/BUILD",
1293 "load(':foo.bzl', 'foo_rule')",
1294 "load(':bar.bzl', 'bar_rule')",
1295 "foo_rule(name = 'foo_rule')",
1296 "alias(name = 'dep_rule', actual=':foo_rule')",
1297 "bar_rule(name = 'my_rule', deps = [':dep_rule'])");
1298 ConfiguredTarget configuredTarget = getConfiguredTarget("//test:my_rule");
dslomov211a3ba2017-05-16 00:21:22 +02001299 Object provider = configuredTarget.get("proxy");
Vladimir Moskva748ba862016-09-20 13:46:11 +00001300 assertThat(provider).isInstanceOf(SkylarkClassObject.class);
vladmos97d67082017-07-13 14:54:03 +02001301 assertThat(((SkylarkClassObject) provider).getConstructor().getKey()).isEqualTo(
1302 new SkylarkKey(Label.parseAbsolute("//test:foo.bzl"), "foo_provider"));
Vladimir Moskva748ba862016-09-20 13:46:11 +00001303 }
1304
1305 @Test
1306 public void testDeclaredProvidersWrongKey() throws Exception {
1307 scratch.file(
1308 "test/foo.bzl",
1309 "foo_provider = provider()",
1310 "unused_provider = provider()",
1311 "def _impl(ctx):",
1312 " foo = foo_provider()",
1313 " return [foo]",
1314 "foo_rule = rule(",
1315 " implementation = _impl,",
1316 " attrs = {",
1317 " \"srcs\": attr.label_list(allow_files=True),",
1318 " }",
1319 ")"
1320 );
1321 scratch.file(
1322 "test/bar.bzl",
1323 "load(':foo.bzl', 'unused_provider')",
1324 "def _impl(ctx):",
1325 " dep = ctx.attr.deps[0]",
1326 " provider = dep[unused_provider]", // Should throw an error here
1327 "bar_rule = rule(",
1328 " implementation = _impl,",
1329 " attrs = {",
1330 " 'srcs': attr.label_list(allow_files=True),",
1331 " 'deps': attr.label_list(allow_files=True),",
1332 " }",
1333 ")"
1334 );
1335 scratch.file(
1336 "test/BUILD",
1337 "load(':foo.bzl', 'foo_rule')",
1338 "load(':bar.bzl', 'bar_rule')",
1339 "foo_rule(name = 'dep_rule')",
1340 "bar_rule(name = 'my_rule', deps = [':dep_rule'])");
1341
1342 try {
1343 getConfiguredTarget("//test:my_rule");
1344 fail();
1345 } catch (AssertionError expected) {
lberkiaea56b32017-05-30 12:35:33 +02001346 assertThat(expected)
1347 .hasMessageThat()
vladmos7f6d3a12017-07-17 23:15:21 +02001348 .contains("<target //test:dep_rule> (rule 'foo_rule') doesn't contain "
1349 + "declared provider 'unused_provider'");
Vladimir Moskva748ba862016-09-20 13:46:11 +00001350 }
1351 }
1352
1353 @Test
1354 public void testDeclaredProvidersInvalidKey() throws Exception {
1355 scratch.file(
1356 "test/foo.bzl",
1357 "foo_provider = provider()",
1358 "def _impl(ctx):",
1359 " foo = foo_provider()",
1360 " return [foo]",
1361 "foo_rule = rule(",
1362 " implementation = _impl,",
1363 " attrs = {",
1364 " \"srcs\": attr.label_list(allow_files=True),",
1365 " }",
1366 ")"
1367 );
1368 scratch.file(
1369 "test/bar.bzl",
1370 "def _impl(ctx):",
1371 " dep = ctx.attr.deps[0]",
1372 " provider = dep['foo_provider']", // Should throw an error here
1373 "bar_rule = rule(",
1374 " implementation = _impl,",
1375 " attrs = {",
1376 " 'srcs': attr.label_list(allow_files=True),",
1377 " 'deps': attr.label_list(allow_files=True),",
1378 " }",
1379 ")"
1380 );
1381 scratch.file(
1382 "test/BUILD",
1383 "load(':foo.bzl', 'foo_rule')",
1384 "load(':bar.bzl', 'bar_rule')",
1385 "foo_rule(name = 'dep_rule')",
1386 "bar_rule(name = 'my_rule', deps = [':dep_rule'])");
1387
1388 try {
1389 getConfiguredTarget("//test:my_rule");
1390 fail();
1391 } catch (AssertionError expected) {
lberkiaea56b32017-05-30 12:35:33 +02001392 assertThat(expected)
1393 .hasMessageThat()
1394 .contains(
vladmos7f6d3a12017-07-17 23:15:21 +02001395 "Type Target only supports indexing by object constructors, got string instead");
Vladimir Moskva748ba862016-09-20 13:46:11 +00001396 }
1397 }
1398
1399 @Test
1400 public void testDeclaredProvidersFileTarget() throws Exception {
1401 scratch.file(
1402 "test/bar.bzl",
1403 "unused_provider = provider()",
1404 "def _impl(ctx):",
1405 " src = ctx.attr.srcs[0]",
1406 " provider = src[unused_provider]", // Should throw an error here
1407 "bar_rule = rule(",
1408 " implementation = _impl,",
1409 " attrs = {",
1410 " 'srcs': attr.label_list(allow_files=True),",
1411 " }",
1412 ")"
1413 );
1414 scratch.file(
1415 "test/BUILD",
1416 "load(':bar.bzl', 'bar_rule')",
1417 "bar_rule(name = 'my_rule', srcs = ['input.txt'])");
1418
1419 try {
1420 getConfiguredTarget("//test:my_rule");
1421 fail();
1422 } catch (AssertionError expected) {
lberkiaea56b32017-05-30 12:35:33 +02001423 assertThat(expected)
1424 .hasMessageThat()
vladmos7f6d3a12017-07-17 23:15:21 +02001425 .contains("<input file target //test:input.txt> doesn't contain "
1426 + "declared provider 'unused_provider'");
Vladimir Moskva748ba862016-09-20 13:46:11 +00001427 }
1428 }
1429
1430 @Test
Vladimir Moskva4f5e12d2016-10-07 16:28:23 +00001431 public void testDeclaredProvidersInOperator() throws Exception {
1432 scratch.file(
1433 "test/foo.bzl",
1434 "foo_provider = provider()",
1435 "bar_provider = provider()",
1436 "",
1437 "def _inner_impl(ctx):",
1438 " foo = foo_provider()",
1439 " return [foo]",
1440 "inner_rule = rule(",
1441 " implementation = _inner_impl,",
1442 ")",
1443 "",
1444 "def _outer_impl(ctx):",
1445 " dep = ctx.attr.deps[0]",
1446 " return struct(",
1447 " foo = (foo_provider in dep),", // Should be true
1448 " bar = (bar_provider in dep),", // Should be false
1449 " )",
1450 "outer_rule = rule(",
1451 " implementation = _outer_impl,",
1452 " attrs = {",
1453 " 'deps': attr.label_list(),",
1454 " }",
1455 ")"
1456 );
1457 scratch.file(
1458 "test/BUILD",
1459 "load(':foo.bzl', 'inner_rule', 'outer_rule')",
1460 "inner_rule(name = 'dep_rule')",
1461 "outer_rule(name = 'my_rule', deps = [':dep_rule'])");
1462
1463 ConfiguredTarget configuredTarget = getConfiguredTarget("//test:my_rule");
dslomov211a3ba2017-05-16 00:21:22 +02001464 Object foo = configuredTarget.get("foo");
Vladimir Moskva4f5e12d2016-10-07 16:28:23 +00001465 assertThat(foo).isInstanceOf(Boolean.class);
1466 assertThat((Boolean) foo).isTrue();
dslomov211a3ba2017-05-16 00:21:22 +02001467 Object bar = configuredTarget.get("bar");
Vladimir Moskva4f5e12d2016-10-07 16:28:23 +00001468 assertThat(bar).isInstanceOf(Boolean.class);
1469 assertThat((Boolean) bar).isFalse();
1470 }
1471
1472 @Test
1473 public void testDeclaredProvidersInOperatorInvalidKey() throws Exception {
1474 scratch.file(
1475 "test/foo.bzl",
1476 "foo_provider = provider()",
1477 "bar_provider = provider()",
1478 "",
1479 "def _inner_impl(ctx):",
1480 " foo = foo_provider()",
1481 " return [foo]",
1482 "inner_rule = rule(",
1483 " implementation = _inner_impl,",
1484 ")",
1485 "",
1486 "def _outer_impl(ctx):",
1487 " dep = ctx.attr.deps[0]",
1488 " 'foo_provider' in dep", // Should throw an error here
1489 "outer_rule = rule(",
1490 " implementation = _outer_impl,",
1491 " attrs = {",
1492 " 'deps': attr.label_list(),",
1493 " }",
1494 ")"
1495 );
1496 scratch.file(
1497 "test/BUILD",
1498 "load(':foo.bzl', 'inner_rule', 'outer_rule')",
1499 "inner_rule(name = 'dep_rule')",
1500 "outer_rule(name = 'my_rule', deps = [':dep_rule'])");
1501
1502 try {
1503 getConfiguredTarget("//test:my_rule");
1504 fail();
1505 } catch (AssertionError expected) {
lberkiaea56b32017-05-30 12:35:33 +02001506 assertThat(expected)
1507 .hasMessageThat()
1508 .contains(
vladmos7f6d3a12017-07-17 23:15:21 +02001509 "Type Target only supports querying by object constructors, got string instead");
Vladimir Moskva4f5e12d2016-10-07 16:28:23 +00001510 }
1511 }
1512
1513 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001514 public void testFilesForFileConfiguredTarget() throws Exception {
1515 Object result =
1516 evalRuleContextCode(createRuleContext("//foo:bar"), "ruleContext.attr.srcs[0].files");
lberkiaea56b32017-05-30 12:35:33 +02001517 assertThat(ActionsTestUtil.baseNamesOf(((SkylarkNestedSet) result).getSet(Artifact.class)))
1518 .isEqualTo("libjl.jar");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001519 }
1520
Florian Weikertb4c59042015-12-01 10:47:18 +00001521 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001522 public void testCtxStructFieldsCustomErrorMessages() throws Exception {
1523 checkErrorContains("No attribute 'foo' in attr.", "ruleContext.attr.foo");
1524 checkErrorContains("No attribute 'foo' in outputs.", "ruleContext.outputs.foo");
1525 checkErrorContains("No attribute 'foo' in files.", "ruleContext.files.foo");
1526 checkErrorContains("No attribute 'foo' in file.", "ruleContext.file.foo");
1527 checkErrorContains("No attribute 'foo' in executable.", "ruleContext.executable.foo");
1528 }
1529
Florian Weikertb4c59042015-12-01 10:47:18 +00001530 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001531 public void testBinDirPath() throws Exception {
1532 SkylarkRuleContext ctx = createRuleContext("//foo:bar");
Kristina Chodorowba41c2d2016-10-10 17:21:24 +00001533 Object result = evalRuleContextCode(ctx, "ruleContext.bin_dir.path");
lberkiaea56b32017-05-30 12:35:33 +02001534 assertThat(result).isEqualTo(ctx.getConfiguration().getBinFragment().getPathString());
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001535 }
1536
Florian Weikertb4c59042015-12-01 10:47:18 +00001537 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001538 public void testEmptyLabelListTypeAttrInCtx() throws Exception {
1539 SkylarkRuleContext ctx = createRuleContext("//foo:baz");
1540 Object result = evalRuleContextCode(ctx, "ruleContext.attr.srcs");
lberkiaea56b32017-05-30 12:35:33 +02001541 assertThat(result).isEqualTo(MutableList.EMPTY);
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001542 }
1543
Florian Weikertb4c59042015-12-01 10:47:18 +00001544 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001545 public void testDefinedMakeVariable() throws Exception {
1546 SkylarkRuleContext ctx = createRuleContext("//foo:baz");
Liam Miller-Cushon191646d2016-01-29 20:14:48 +00001547 String java = (String) evalRuleContextCode(ctx, "ruleContext.var['JAVA']");
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001548 // Get the last path segment
Liam Miller-Cushon191646d2016-01-29 20:14:48 +00001549 java = java.substring(java.lastIndexOf('/'));
lberkiaea56b32017-05-30 12:35:33 +02001550 assertThat(java).isEqualTo("/java" + OsUtils.executableExtension());
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001551 }
1552
Florian Weikertb4c59042015-12-01 10:47:18 +00001553 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001554 public void testCodeCoverageConfigurationAccess() throws Exception {
1555 SkylarkRuleContext ctx = createRuleContext("//foo:baz");
1556 boolean coverage =
1557 (Boolean) evalRuleContextCode(ctx, "ruleContext.configuration.coverage_enabled");
lberkiaea56b32017-05-30 12:35:33 +02001558 assertThat(ctx.getRuleContext().getConfiguration().isCodeCoverageEnabled()).isEqualTo(coverage);
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001559 }
1560
1561 @Override
1562 protected void checkErrorContains(String errorMsg, String... lines) throws Exception {
1563 super.checkErrorContains(createRuleContext("//foo:foo"), errorMsg, lines);
1564 }
1565
1566 /**
1567 * Checks whether the given (invalid) statement leads to the expected error
1568 */
1569 private void checkReportedErrorStartsWith(
1570 SkylarkRuleContext ruleContext, String errorMsg, String... statements) throws Exception {
1571 // If the component under test relies on Reporter and EventCollector for error handling, any
1572 // error would lead to an asynchronous AssertionFailedError thanks to failFastHandler in
1573 // FoundationTestCase.
1574 //
1575 // Consequently, we disable failFastHandler and check all events for the expected error message
1576 reporter.removeHandler(failFastHandler);
1577
1578 Object result = evalRuleContextCode(ruleContext, statements);
1579
1580 String first = null;
1581 int count = 0;
1582
1583 try {
1584 for (Event evt : eventCollector) {
1585 if (evt.getMessage().startsWith(errorMsg)) {
1586 return;
1587 }
1588
1589 ++count;
1590 first = evt.getMessage();
1591 }
1592
1593 if (count == 0) {
1594 fail(
1595 String.format(
1596 "checkReportedErrorStartsWith(): There was no error; the result is '%s'", result));
1597 } else {
1598 fail(
1599 String.format(
1600 "Found %d error(s), but none with the expected message '%s'. First error: '%s'",
Yun Pengfc610052016-06-20 11:44:06 +00001601 count, errorMsg, first));
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001602 }
1603 } finally {
1604 eventCollector.clear();
1605 }
1606 }
1607
Florian Weikertb4c59042015-12-01 10:47:18 +00001608 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001609 public void testStackTraceWithoutOriginalMessage() throws Exception {
1610 setupThrowFunction(
1611 new BuiltinFunction("throw") {
1612 @SuppressWarnings("unused")
1613 public Object invoke() throws Exception {
1614 throw new ThereIsNoMessageException();
1615 }
1616 });
1617
1618 checkEvalErrorContains(
laurentlb59800122017-07-03 11:42:25 -04001619 "There Is No Message: SkylarkRuleImplementationFunctionsTest",
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001620 "throw()");
1621 }
1622
Florian Weikertb4c59042015-12-01 10:47:18 +00001623 @Test
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001624 public void testNoStackTraceOnInterrupt() throws Exception {
1625 setupThrowFunction(
1626 new BuiltinFunction("throw") {
1627 @SuppressWarnings("unused")
1628 public Object invoke() throws Exception {
1629 throw new InterruptedException();
1630 }
1631 });
1632 try {
1633 eval("throw()");
1634 fail("Expected an InterruptedException");
1635 } catch (InterruptedException ex) {
1636 // Expected.
1637 }
1638 }
1639
Florian Weikertb4c59042015-12-01 10:47:18 +00001640 @Test
Florian Weikert3c5f5342015-09-24 17:29:04 +00001641 public void testGlobInImplicitOutputs() throws Exception {
Yun Pengfc610052016-06-20 11:44:06 +00001642 scratch.file(
1643 "test/glob.bzl",
Florian Weikert3c5f5342015-09-24 17:29:04 +00001644 "def _impl(ctx):",
1645 " ctx.empty_action(",
1646 " inputs = [],",
1647 " )",
Florian Weikert3ae59122016-06-06 09:11:43 +00001648 "def _foo():",
Florian Weikert3c5f5342015-09-24 17:29:04 +00001649 " return native.glob(['*'])",
1650 "glob_rule = rule(",
1651 " implementation = _impl,",
1652 " outputs = _foo,",
1653 ")");
Yun Pengfc610052016-06-20 11:44:06 +00001654 scratch.file(
1655 "test/BUILD",
Florian Weikert3c5f5342015-09-24 17:29:04 +00001656 "load('/test/glob', 'glob_rule')",
1657 "glob_rule(name = 'my_glob',",
1658 " srcs = ['foo.bar', 'other_foo.bar'])");
1659 reporter.removeHandler(failFastHandler);
1660 getConfiguredTarget("//test:my_glob");
1661 assertContainsEvent("native.glob() can only be called during the loading phase");
1662 }
1663
Francois-Rene Rideau1bae01f2016-01-30 04:25:58 +00001664 @Test
Laurent Le Brun1d19f3d2016-05-13 12:20:36 +00001665 public void testRuleFromBzlFile() throws Exception {
Yun Pengfc610052016-06-20 11:44:06 +00001666 scratch.file("test/rule.bzl", "def _impl(ctx): return", "foo = rule(implementation = _impl)");
1667 scratch.file("test/ext.bzl", "load('//test:rule.bzl', 'foo')", "a = 1", "foo(name = 'x')");
1668 scratch.file("test/BUILD", "load('//test:ext.bzl', 'a')");
Laurent Le Brun1d19f3d2016-05-13 12:20:36 +00001669 reporter.removeHandler(failFastHandler);
1670 getConfiguredTarget("//test:x");
1671 assertContainsEvent("Cannot instantiate a rule when loading a .bzl file");
1672 }
1673
1674 @Test
Francois-Rene Rideau1bae01f2016-01-30 04:25:58 +00001675 public void testImplicitOutputsFromGlob() throws Exception {
Yun Pengfc610052016-06-20 11:44:06 +00001676 scratch.file(
1677 "test/glob.bzl",
Francois-Rene Rideau1bae01f2016-01-30 04:25:58 +00001678 "def _impl(ctx):",
1679 " outs = ctx.outputs",
1680 " for i in ctx.attr.srcs:",
1681 " o = getattr(outs, 'foo_' + i.label.name)",
dslomov90ccaa52017-06-30 12:21:28 +02001682 " ctx.actions.write(",
Francois-Rene Rideau1bae01f2016-01-30 04:25:58 +00001683 " output = o,",
1684 " content = 'hoho')",
1685 "",
Florian Weikert3ae59122016-06-06 09:11:43 +00001686 "def _foo(srcs):",
Francois-Rene Rideau1bae01f2016-01-30 04:25:58 +00001687 " outs = {}",
Florian Weikert3ae59122016-06-06 09:11:43 +00001688 " for i in srcs:",
Francois-Rene Rideau1bae01f2016-01-30 04:25:58 +00001689 " outs['foo_' + i.name] = i.name + '.out'",
1690 " return outs",
1691 "",
1692 "glob_rule = rule(",
1693 " attrs = {",
1694 " 'srcs': attr.label_list(allow_files = True),",
1695 " },",
1696 " outputs = _foo,",
1697 " implementation = _impl,",
1698 ")");
1699 scratch.file("test/a.bar", "a");
1700 scratch.file("test/b.bar", "b");
Yun Pengfc610052016-06-20 11:44:06 +00001701 scratch.file(
1702 "test/BUILD",
Francois-Rene Rideau1bae01f2016-01-30 04:25:58 +00001703 "load('/test/glob', 'glob_rule')",
1704 "glob_rule(name = 'my_glob', srcs = glob(['*.bar']))");
1705 ConfiguredTarget ct = getConfiguredTarget("//test:my_glob");
1706 assertThat(ct).isNotNull();
1707 assertThat(getGeneratingAction(getBinArtifact("a.bar.out", ct))).isNotNull();
1708 assertThat(getGeneratingAction(getBinArtifact("b.bar.out", ct))).isNotNull();
1709 }
1710
Vladimir Moskva658a8ea2016-09-02 15:39:17 +00001711 @Test
1712 public void testBuiltInFunctionAsRuleImplementation() throws Exception {
1713 // Using built-in functions as rule implementations shouldn't cause runtime errors
1714 scratch.file(
1715 "test/rule.bzl",
1716 "silly_rule = rule(",
1717 " implementation = int,",
1718 " attrs = {",
1719 " \"srcs\": attr.label_list(allow_files=True),",
1720 " }",
1721 ")"
1722 );
1723 scratch.file(
1724 "test/BUILD",
1725 "load('/test/rule', 'silly_rule')",
1726 "silly_rule(name = 'silly')");
1727 thrown.handleAssertionErrors(); // Compatibility with JUnit 4.11
1728 thrown.expect(AssertionError.class);
vladmos25ef6a82017-07-07 11:45:01 -04001729 thrown.expectMessage("<rule context for //test:silly> is not of type string or int or bool");
Vladimir Moskva658a8ea2016-09-02 15:39:17 +00001730 getConfiguredTarget("//test:silly");
1731 }
1732
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001733 private void setupThrowFunction(BuiltinFunction func) throws Exception {
1734 throwFunction = func;
1735 throwFunction.configure(
1736 getClass().getDeclaredField("throwFunction").getAnnotation(SkylarkSignature.class));
1737 update("throw", throwFunction);
1738 }
1739
1740 private static class ThereIsNoMessageException extends EvalException {
1741 public ThereIsNoMessageException() {
1742 super(null, "This is not the message you are looking for."); // Unused dummy message
1743 }
1744
1745 @Override
1746 public String getMessage() {
1747 return "";
1748 }
1749 }
1750}