blob: 3375361df36bf10287b2a97685737c1dffd5a064 [file] [log] [blame]
juliexxiacb9b2af2018-11-30 17:21:22 -08001// Copyright 2018 The Bazel Authors. All rights reserved.
2//
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
laurentlbc67c5702020-07-30 09:25:45 -070015package com.google.devtools.build.lib.starlark;
juliexxiacb9b2af2018-11-30 17:21:22 -080016
17import static com.google.common.truth.Truth.assertThat;
michajlo660d17f2020-03-27 09:01:57 -070018import static org.junit.Assert.assertThrows;
juliexxiacb9b2af2018-11-30 17:21:22 -080019
Julie Xia69d4ace2020-05-29 11:25:25 -070020import com.google.common.collect.ImmutableList;
gregcebf31feb2020-12-08 08:23:18 -080021import com.google.devtools.build.lib.events.Event;
22import com.google.devtools.build.lib.events.ExtendedEventHandler;
23import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable;
24import com.google.devtools.build.lib.pkgcache.TargetParsingCompleteEvent;
laurentlbc67c5702020-07-30 09:25:45 -070025import com.google.devtools.build.lib.starlark.util.StarlarkOptionsTestCase;
juliexxiacb9b2af2018-11-30 17:21:22 -080026import com.google.devtools.common.options.OptionsParsingException;
27import com.google.devtools.common.options.OptionsParsingResult;
gregcebf31feb2020-12-08 08:23:18 -080028import java.util.ArrayList;
29import java.util.List;
30import java.util.stream.Collectors;
adonovan3ed7ed52020-09-30 12:03:28 -070031import net.starlark.java.eval.StarlarkInt;
gregcebf31feb2020-12-08 08:23:18 -080032import org.junit.Before;
juliexxiacb9b2af2018-11-30 17:21:22 -080033import org.junit.Test;
34import org.junit.runner.RunWith;
35import org.junit.runners.JUnit4;
36
37/** Unit test for the {@code StarlarkOptionsParser}. */
38@RunWith(JUnit4.class)
jcater741926e2019-12-02 06:50:08 -080039public class StarlarkOptionsParsingTest extends StarlarkOptionsTestCase {
juliexxiacb9b2af2018-11-30 17:21:22 -080040
gregcebf31feb2020-12-08 08:23:18 -080041 private List<Postable> postedEvents;
42
43 @Before
44 public void addPostableEventHandler() {
45 postedEvents = new ArrayList<>();
46 reporter.addHandler(
47 new ExtendedEventHandler() {
48 @Override
49 public void post(Postable obj) {
50 postedEvents.add(obj);
51 }
52
53 @Override
54 public void handle(Event event) {}
55 });
56 }
57
58 /** Returns only the posted events of the given class. */
59 private List<Postable> eventsOfType(Class<? extends Postable> clazz) {
60 return postedEvents.stream()
61 .filter(event -> event.getClass().equals(clazz))
62 .collect(Collectors.toList());
63 }
64
juliexxiacb9b2af2018-11-30 17:21:22 -080065 // test --flag=value
66 @Test
67 public void testFlagEqualsValueForm() throws Exception {
68 writeBasicIntFlag();
69
70 OptionsParsingResult result = parseStarlarkOptions("--//test:my_int_setting=666");
71
72 assertThat(result.getStarlarkOptions()).hasSize(1);
adonovan3ed7ed52020-09-30 12:03:28 -070073 assertThat(result.getStarlarkOptions().get("//test:my_int_setting"))
74 .isEqualTo(StarlarkInt.of(666));
juliexxiacb9b2af2018-11-30 17:21:22 -080075 assertThat(result.getResidue()).isEmpty();
76 }
77
juliexxiac2285582021-01-07 09:13:36 -080078 // test --@main_workspace//flag=value parses out to //flag=value
79 // test --@other_workspace//flag=value parses out to @other_workspace//flag=value
John Millikinfff73092019-10-22 15:12:32 -070080 @Test
81 public void testFlagNameWithWorkspace() throws Exception {
82 writeBasicIntFlag();
juliexxiac2285582021-01-07 09:13:36 -080083 scratch.file("test/repo2/WORKSPACE");
84 scratch.file(
85 "test/repo2/defs.bzl",
Googler09bf5472024-03-28 10:08:10 -070086 """
87 def _impl(ctx):
88 pass
89
90 my_flag = rule(
91 implementation = _impl,
92 build_setting = config.int(flag = True),
93 )
94 """);
juliexxiac2285582021-01-07 09:13:36 -080095 scratch.file(
96 "test/repo2/BUILD",
Googler09bf5472024-03-28 10:08:10 -070097 """
98 load(":defs.bzl", "my_flag")
99
100 my_flag(
101 name = "flag2",
102 build_setting_default = 2,
103 )
104 """);
juliexxiac2285582021-01-07 09:13:36 -0800105
106 rewriteWorkspace(
107 "workspace(name = 'starlark_options_test')",
108 "local_repository(",
109 " name = 'repo2',",
110 " path = 'test/repo2',",
111 ")");
John Millikinfff73092019-10-22 15:12:32 -0700112
113 OptionsParsingResult result =
juliexxiac2285582021-01-07 09:13:36 -0800114 parseStarlarkOptions(
Googlerf272df32023-02-03 15:07:37 -0800115 "--@starlark_options_test//test:my_int_setting=666 --@repo2//:flag2=222",
116 /* onlyStarlarkParser= */ true);
John Millikinfff73092019-10-22 15:12:32 -0700117
juliexxiac2285582021-01-07 09:13:36 -0800118 assertThat(result.getStarlarkOptions()).hasSize(2);
119 assertThat(result.getStarlarkOptions().get("//test:my_int_setting"))
adonovan3ed7ed52020-09-30 12:03:28 -0700120 .isEqualTo(StarlarkInt.of(666));
Googleref457ae2023-11-10 09:39:21 -0800121 assertThat(result.getStarlarkOptions().get("@@repo2//:flag2")).isEqualTo(StarlarkInt.of(222));
John Millikinfff73092019-10-22 15:12:32 -0700122 assertThat(result.getResidue()).isEmpty();
123 }
124
juliexxiacb9b2af2018-11-30 17:21:22 -0800125 // test --fake_flag=value
126 @Test
127 public void testBadFlag_equalsForm() throws Exception {
128 scratch.file("test/BUILD");
129 reporter.removeHandler(failFastHandler);
130
131 OptionsParsingException e =
132 assertThrows(
133 OptionsParsingException.class,
134 () -> parseStarlarkOptions("--//fake_flag=blahblahblah"));
135
136 assertThat(e).hasMessageThat().contains("Error loading option //fake_flag");
Googlerddb9b9a2020-06-26 12:50:43 -0700137 assertThat(e.getInvalidArgument()).isEqualTo("//fake_flag");
juliexxiacb9b2af2018-11-30 17:21:22 -0800138 }
139
juliexxiacb9b2af2018-11-30 17:21:22 -0800140 // test --fake_flag
141 @Test
142 public void testBadFlag_boolForm() throws Exception {
143 scratch.file("test/BUILD");
144 reporter.removeHandler(failFastHandler);
145
146 OptionsParsingException e =
147 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//fake_flag"));
148
149 assertThat(e).hasMessageThat().contains("Error loading option //fake_flag");
Googlerddb9b9a2020-06-26 12:50:43 -0700150 assertThat(e.getInvalidArgument()).isEqualTo("//fake_flag");
juliexxiacb9b2af2018-11-30 17:21:22 -0800151 }
152
juliexxiacb9b2af2018-11-30 17:21:22 -0800153 @Test
gregceae07b7c2020-12-07 11:00:04 -0800154 public void testBadFlag_keepGoing() throws Exception {
155 optionsParser.parse("--keep_going");
156 scratch.file("test/BUILD");
157 reporter.removeHandler(failFastHandler);
158
159 OptionsParsingException e =
160 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//fake_flag"));
161
162 assertThat(e).hasMessageThat().contains("Error loading option //fake_flag");
163 assertThat(e.getInvalidArgument()).isEqualTo("//fake_flag");
164 }
165
166 @Test
juliexxiacb9b2af2018-11-30 17:21:22 -0800167 public void testSingleDash_notAllowed() throws Exception {
juliexxiacb9b2af2018-11-30 17:21:22 -0800168 writeBasicIntFlag();
169
Fabian Meumertzheim9f2542f2022-08-16 08:29:35 -0700170 OptionsParsingException e =
171 assertThrows(
172 OptionsParsingException.class,
Googlerf272df32023-02-03 15:07:37 -0800173 () ->
174 parseStarlarkOptions("-//test:my_int_setting=666", /* onlyStarlarkParser= */ true));
Fabian Meumertzheim9f2542f2022-08-16 08:29:35 -0700175 assertThat(e).hasMessageThat().isEqualTo("Invalid options syntax: -//test:my_int_setting=666");
juliexxiacb9b2af2018-11-30 17:21:22 -0800176 }
177
178 // test --non_flag_setting=value
179 @Test
180 public void testNonFlagParsing() throws Exception {
juliexxiacb9b2af2018-11-30 17:21:22 -0800181 scratch.file(
182 "test/build_setting.bzl",
Googler09bf5472024-03-28 10:08:10 -0700183 """
184 def _build_setting_impl(ctx):
185 return []
186
187 int_flag = rule(
188 implementation = _build_setting_impl,
189 build_setting = config.int(flag = False),
190 )
191 """);
juliexxiacb9b2af2018-11-30 17:21:22 -0800192 scratch.file(
193 "test/BUILD",
Googler09bf5472024-03-28 10:08:10 -0700194 """
195 load("//test:build_setting.bzl", "int_flag")
196
197 int_flag(
198 name = "my_int_setting",
199 build_setting_default = 42,
200 )
201 """);
juliexxiacb9b2af2018-11-30 17:21:22 -0800202
203 OptionsParsingException e =
204 assertThrows(
205 OptionsParsingException.class,
206 () -> parseStarlarkOptions("--//test:my_int_setting=666"));
207
208 assertThat(e).hasMessageThat().isEqualTo("Unrecognized option: //test:my_int_setting=666");
209 }
210
juliexxiacb9b2af2018-11-30 17:21:22 -0800211 // test --bool_flag
212 @Test
213 public void testBooleanFlag() throws Exception {
214 writeBasicBoolFlag();
215
juliexxiad2860842019-06-05 12:30:35 -0700216 OptionsParsingResult result = parseStarlarkOptions("--//test:my_bool_setting=false");
juliexxiacb9b2af2018-11-30 17:21:22 -0800217
218 assertThat(result.getStarlarkOptions()).hasSize(1);
juliexxiad2860842019-06-05 12:30:35 -0700219 assertThat(result.getStarlarkOptions().get("//test:my_bool_setting")).isEqualTo(false);
juliexxiacb9b2af2018-11-30 17:21:22 -0800220 assertThat(result.getResidue()).isEmpty();
221 }
222
223 // test --nobool_flag
224 @Test
225 public void testNoPrefixedBooleanFlag() throws Exception {
226 writeBasicBoolFlag();
227
228 OptionsParsingResult result = parseStarlarkOptions("--no//test:my_bool_setting");
229
230 assertThat(result.getStarlarkOptions()).hasSize(1);
231 assertThat(result.getStarlarkOptions().get("//test:my_bool_setting")).isEqualTo(false);
232 assertThat(result.getResidue()).isEmpty();
233 }
234
Ryan Beasley32d52682021-05-07 13:35:46 -0700235 // test --no@main_workspace//:bool_flag
236 @Test
237 public void testNoPrefixedBooleanFlag_withWorkspace() throws Exception {
238 writeBasicBoolFlag();
239
240 OptionsParsingResult result = parseStarlarkOptions("--no@//test:my_bool_setting");
241
242 assertThat(result.getStarlarkOptions()).hasSize(1);
243 assertThat(result.getStarlarkOptions().get("//test:my_bool_setting")).isEqualTo(false);
244 assertThat(result.getResidue()).isEmpty();
245 }
246
juliexxiacb9b2af2018-11-30 17:21:22 -0800247 // test --noint_flag
248 @Test
249 public void testNoPrefixedNonBooleanFlag() throws Exception {
250 writeBasicIntFlag();
251
252 OptionsParsingException e =
253 assertThrows(
254 OptionsParsingException.class, () -> parseStarlarkOptions("--no//test:my_int_setting"));
255
256 assertThat(e)
257 .hasMessageThat()
258 .isEqualTo("Illegal use of 'no' prefix on non-boolean option: //test:my_int_setting");
259 }
260
261 // test --int_flag
262 @Test
263 public void testFlagWithoutValue() throws Exception {
264 writeBasicIntFlag();
265
266 OptionsParsingException e =
267 assertThrows(
268 OptionsParsingException.class, () -> parseStarlarkOptions("--//test:my_int_setting"));
269
270 assertThat(e).hasMessageThat().isEqualTo("Expected value after --//test:my_int_setting");
271 }
272
273 // test --flag --flag
274 @Test
275 public void testRepeatFlagLastOneWins() throws Exception {
276 writeBasicIntFlag();
277
278 OptionsParsingResult result =
279 parseStarlarkOptions("--//test:my_int_setting=4 --//test:my_int_setting=7");
280
281 assertThat(result.getStarlarkOptions()).hasSize(1);
adonovan3ed7ed52020-09-30 12:03:28 -0700282 assertThat(result.getStarlarkOptions().get("//test:my_int_setting"))
283 .isEqualTo(StarlarkInt.of(7));
juliexxiacb9b2af2018-11-30 17:21:22 -0800284 assertThat(result.getResidue()).isEmpty();
285 }
286
287 // test --flagA=valueA --flagB=valueB
288 @Test
289 public void testMultipleFlags() throws Exception {
juliexxiacb9b2af2018-11-30 17:21:22 -0800290 scratch.file(
291 "test/build_setting.bzl",
Googler09bf5472024-03-28 10:08:10 -0700292 """
293 def _build_setting_impl(ctx):
294 return []
295
296 int_flag = rule(
297 implementation = _build_setting_impl,
298 build_setting = config.int(flag = True),
299 )
300 """);
juliexxiacb9b2af2018-11-30 17:21:22 -0800301 scratch.file(
302 "test/BUILD",
Googler09bf5472024-03-28 10:08:10 -0700303 """
304 load("//test:build_setting.bzl", "int_flag")
305
306 int_flag(
307 name = "my_int_setting",
308 build_setting_default = 42,
309 )
310
311 int_flag(
312 name = "my_other_int_setting",
313 build_setting_default = 77,
314 )
315 """);
juliexxiacb9b2af2018-11-30 17:21:22 -0800316
317 OptionsParsingResult result =
318 parseStarlarkOptions("--//test:my_int_setting=0 --//test:my_other_int_setting=0");
319
320 assertThat(result.getResidue()).isEmpty();
321 assertThat(result.getStarlarkOptions()).hasSize(2);
adonovan3ed7ed52020-09-30 12:03:28 -0700322 assertThat(result.getStarlarkOptions().get("//test:my_int_setting"))
323 .isEqualTo(StarlarkInt.of(0));
324 assertThat(result.getStarlarkOptions().get("//test:my_other_int_setting"))
325 .isEqualTo(StarlarkInt.of(0));
juliexxiacb9b2af2018-11-30 17:21:22 -0800326 }
327
328 // test --non_build_setting
329 @Test
330 public void testNonBuildSetting() throws Exception {
331 scratch.file(
332 "test/rules.bzl",
Googler09bf5472024-03-28 10:08:10 -0700333 """
334 def _impl(ctx):
335 return []
336
337 my_rule = rule(
338 implementation = _impl,
339 )
340 """);
341 scratch.file(
342 "test/BUILD",
343 """
344 load("//test:rules.bzl", "my_rule")
345
346 my_rule(name = "my_rule")
347 """);
juliexxiacb9b2af2018-11-30 17:21:22 -0800348 OptionsParsingException e =
349 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//test:my_rule"));
350 assertThat(e).hasMessageThat().isEqualTo("Unrecognized option: //test:my_rule");
351 }
352
353 // test --non_rule_configured_target
354 @Test
355 public void testNonRuleConfiguredTarget() throws Exception {
356 scratch.file(
357 "test/BUILD",
Googler09bf5472024-03-28 10:08:10 -0700358 """
359 genrule(
360 name = "my_gen",
361 srcs = ["x.in"],
362 outs = ["x.cc"],
363 cmd = "$(locations :tool) $< >$@",
364 tools = [":tool"],
365 )
366
367 cc_library(name = "tool-dep")
368 """);
juliexxiacb9b2af2018-11-30 17:21:22 -0800369 OptionsParsingException e =
370 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//test:x.in"));
371 assertThat(e).hasMessageThat().isEqualTo("Unrecognized option: //test:x.in");
372 }
373
374 // test --int_flag=non_int_value
375 @Test
376 public void testWrongValueType_int() throws Exception {
377 writeBasicIntFlag();
378
379 OptionsParsingException e =
380 assertThrows(
381 OptionsParsingException.class,
382 () -> parseStarlarkOptions("--//test:my_int_setting=woohoo"));
383
384 assertThat(e)
385 .hasMessageThat()
386 .isEqualTo("While parsing option //test:my_int_setting=woohoo: 'woohoo' is not a int");
387 }
388
389 // test --bool_flag=non_bool_value
390 @Test
391 public void testWrongValueType_bool() throws Exception {
392 writeBasicBoolFlag();
393
394 OptionsParsingException e =
395 assertThrows(
396 OptionsParsingException.class,
397 () -> parseStarlarkOptions("--//test:my_bool_setting=woohoo"));
398
399 assertThat(e)
400 .hasMessageThat()
401 .isEqualTo("While parsing option //test:my_bool_setting=woohoo: 'woohoo' is not a boolean");
402 }
juliexxiad2860842019-06-05 12:30:35 -0700403
404 // test --int-flag=same value as default
405 @Test
406 public void testDontStoreDefaultValue() throws Exception {
407 // build_setting_default = 42
408 writeBasicIntFlag();
409
410 OptionsParsingResult result = parseStarlarkOptions("--//test:my_int_setting=42");
411
412 assertThat(result.getStarlarkOptions()).isEmpty();
413 }
schmitt8fd43cf2019-11-19 15:49:27 -0800414
415 @Test
416 public void testOptionsAreParsedWithBuildTestsOnly() throws Exception {
417 writeBasicIntFlag();
418 optionsParser.parse("--build_tests_only");
419
420 OptionsParsingResult result = parseStarlarkOptions("--//test:my_int_setting=15");
421
adonovan3ed7ed52020-09-30 12:03:28 -0700422 assertThat(result.getStarlarkOptions().get("//test:my_int_setting"))
423 .isEqualTo(StarlarkInt.of(15));
schmitt8fd43cf2019-11-19 15:49:27 -0800424 }
Julie Xia69d4ace2020-05-29 11:25:25 -0700425
gregcebf31feb2020-12-08 08:23:18 -0800426 /**
427 * When Starlark flags are only set as flags, they shouldn't produce {@link
428 * TargetParsingCompleteEvent}s. That's intended to communicate (to the build event protocol)
429 * which of the targets in {@code blaze build //foo:all //bar:all} were built.
430 */
431 @Test
432 public void testExpectedBuildEventOutput_asFlag() throws Exception {
433 writeBasicIntFlag();
434 scratch.file("blah/BUILD", "cc_library(name = 'mylib')");
Googler1ee0f642024-02-09 06:30:35 -0800435 useConfiguration("--//test:my_int_setting=15");
gregcebf31feb2020-12-08 08:23:18 -0800436 update(
437 ImmutableList.of("//blah:mylib"),
438 /*keepGoing=*/ false,
439 /*loadingPhaseThreads=*/ LOADING_PHASE_THREADS,
440 /*doAnalysis*/ true,
441 eventBus);
442 List<Postable> targetParsingCompleteEvents = eventsOfType(TargetParsingCompleteEvent.class);
443 assertThat(targetParsingCompleteEvents).hasSize(1);
444 assertThat(
445 ((TargetParsingCompleteEvent) targetParsingCompleteEvents.get(0))
446 .getOriginalTargetPattern())
447 .containsExactly("//blah:mylib");
448 }
449
450 /**
451 * But Starlark are also targets. When they're requested as normal build targets they should
452 * produce {@link TargetParsingCompleteEvent} just like any other target.
453 */
454 @Test
455 public void testExpectedBuildEventOutput_asTarget() throws Exception {
456 writeBasicIntFlag();
457 scratch.file("blah/BUILD", "cc_library(name = 'mylib')");
Googler1ee0f642024-02-09 06:30:35 -0800458 useConfiguration("--//test:my_int_setting=15");
gregcebf31feb2020-12-08 08:23:18 -0800459 update(
460 ImmutableList.of("//blah:mylib", "//test:my_int_setting"),
461 /*keepGoing=*/ false,
462 /*loadingPhaseThreads=*/ LOADING_PHASE_THREADS,
463 /*doAnalysis*/ true,
464 eventBus);
465 List<Postable> targetParsingCompleteEvents = eventsOfType(TargetParsingCompleteEvent.class);
466 assertThat(targetParsingCompleteEvents).hasSize(1);
467 assertThat(
468 ((TargetParsingCompleteEvent) targetParsingCompleteEvents.get(0))
469 .getOriginalTargetPattern())
470 .containsExactly("//blah:mylib", "//test:my_int_setting");
471 }
juliexxiaa13f5902020-12-10 09:19:01 -0800472
473 @Test
474 @SuppressWarnings("unchecked")
475 public void testAllowMultipleStringFlag() throws Exception {
476 scratch.file(
477 "test/build_setting.bzl",
Googler09bf5472024-03-28 10:08:10 -0700478 """
479 def _build_setting_impl(ctx):
480 return []
481
482 allow_multiple_flag = rule(
483 implementation = _build_setting_impl,
484 build_setting = config.string(flag = True, allow_multiple = True),
485 )
486 """);
juliexxiaa13f5902020-12-10 09:19:01 -0800487 scratch.file(
488 "test/BUILD",
Googler09bf5472024-03-28 10:08:10 -0700489 """
490 load("//test:build_setting.bzl", "allow_multiple_flag")
491
492 allow_multiple_flag(
493 name = "cats",
494 build_setting_default = "tabby",
495 )
496 """);
juliexxiaa13f5902020-12-10 09:19:01 -0800497
498 OptionsParsingResult result = parseStarlarkOptions("--//test:cats=calico --//test:cats=bengal");
499
500 assertThat(result.getStarlarkOptions().keySet()).containsExactly("//test:cats");
501 assertThat((List<String>) result.getStarlarkOptions().get("//test:cats"))
502 .containsExactly("calico", "bengal");
503 }
Fabian Meumertzheimcdf01a32022-07-20 08:22:48 -0700504
505 @Test
506 @SuppressWarnings("unchecked")
507 public void testRepeatedStringListFlag() throws Exception {
508 scratch.file(
509 "test/build_setting.bzl",
Googler09bf5472024-03-28 10:08:10 -0700510 """
511 def _build_setting_impl(ctx):
512 return []
513
514 repeated_flag = rule(
515 implementation = _build_setting_impl,
516 build_setting = config.string_list(flag = True, repeatable = True),
517 )
518 """);
Fabian Meumertzheimcdf01a32022-07-20 08:22:48 -0700519 scratch.file(
520 "test/BUILD",
Googler09bf5472024-03-28 10:08:10 -0700521 """
522 load("//test:build_setting.bzl", "repeated_flag")
523
524 repeated_flag(
525 name = "cats",
526 build_setting_default = ["tabby"],
527 )
528 """);
Fabian Meumertzheimcdf01a32022-07-20 08:22:48 -0700529
530 OptionsParsingResult result = parseStarlarkOptions("--//test:cats=calico --//test:cats=bengal");
531
532 assertThat(result.getStarlarkOptions().keySet()).containsExactly("//test:cats");
533 assertThat((List<String>) result.getStarlarkOptions().get("//test:cats"))
534 .containsExactly("calico", "bengal");
535 }
Googler96864602023-06-12 17:41:24 -0700536
537 @Test
538 public void flagReferencesExactlyOneTarget() throws Exception {
539 scratch.file(
540 "test/build_setting.bzl",
Googler09bf5472024-03-28 10:08:10 -0700541 """
542 string_flag = rule(
543 implementation = lambda ctx, attr: [],
544 build_setting = config.string(flag = True),
545 )
546 """);
Googler96864602023-06-12 17:41:24 -0700547 scratch.file(
548 "test/BUILD",
Googler09bf5472024-03-28 10:08:10 -0700549 """
550 load("//test:build_setting.bzl", "string_flag")
551
552 string_flag(
553 name = "one",
554 build_setting_default = "",
555 )
556
557 string_flag(
558 name = "two",
559 build_setting_default = "",
560 )
561 """);
Googler96864602023-06-12 17:41:24 -0700562
563 OptionsParsingException e =
564 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//test:all"));
565
566 assertThat(e)
567 .hasMessageThat()
568 .contains("//test:all: user-defined flags must reference exactly one target");
569 }
Fabian Meumertzheim43fdcd32024-05-01 16:02:55 -0700570
571 @Test
572 public void flagIsAlias() throws Exception {
573 scratch.file(
574 "test/build_setting.bzl",
575 """
576 string_flag = rule(
577 implementation = lambda ctx: [],
578 build_setting = config.string(flag = True),
579 )
580 """);
581 scratch.file(
582 "test/BUILD",
583 """
584 load("//test:build_setting.bzl", "string_flag")
585
586 alias(
587 name = "one",
588 actual = "//test/pkg:two",
589 )
590
591 string_flag(
592 name = "three",
593 build_setting_default = "",
594 )
595 """);
596 scratch.file(
597 "test/pkg/BUILD",
598 """
599 alias(
600 name = "two",
601 actual = "//test:three",
602 )
603 """);
604
605 OptionsParsingResult result = parseStarlarkOptions("--//test:one=one --//test/pkg:two=two");
606
607 assertThat(result.getStarlarkOptions()).containsExactly("//test:three", "two");
608 }
609
610 @Test
611 public void flagIsAlias_cycle() throws Exception {
612 scratch.file(
613 "test/BUILD",
614 """
615 alias(
616 name = "one",
617 actual = "//test/pkg:two",
618 )
619
620 alias(
621 name = "three",
622 actual = ":one",
623 )
624 """);
625 scratch.file(
626 "test/pkg/BUILD",
627 """
628 alias(
629 name = "two",
630 actual = "//test:three",
631 )
632 """);
633
634 OptionsParsingException e =
635 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//test:one=one"));
636
637 assertThat(e)
638 .hasMessageThat()
639 .isEqualTo(
640 "Failed to load build setting '//test:one' due to a cycle in alias chain: //test:one"
641 + " -> //test/pkg:two -> //test:three -> //test:one");
642 }
643
644 @Test
645 public void flagIsAlias_usesSelect() throws Exception {
646 scratch.file(
647 "test/BUILD",
648 """
649 alias(
650 name = "one",
651 actual = "//test/pkg:two",
652 )
653
654 alias(
655 name = "three",
656 actual = ":one",
657 )
658 """);
659 scratch.file(
660 "test/pkg/BUILD",
661 """
662 alias(
663 name = "two",
664 actual = select({"//conditions:default": "//test:three"}),
665 )
666 """);
667
668 OptionsParsingException e =
669 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//test:one=one"));
670
671 assertThat(e)
672 .hasMessageThat()
673 .isEqualTo(
674 "Failed to load build setting '//test:one' as it resolves to an alias with an actual"
675 + " value that uses select(): //test:one -> //test/pkg:two. This is not supported"
676 + " as build settings are needed to determine the configuration the select is"
677 + " evaluated in.");
678 }
679
680 @Test
681 public void flagIsAlias_resolvesToNonBuildSettingTarget() throws Exception {
682 scratch.file(
683 "test/BUILD",
684 """
685 alias(
686 name = "one",
687 actual = "//test/pkg:two",
688 )
689
690 genrule(
691 name = "three",
692 outs = ["out"],
693 cmd = "echo hello > $@",
694 )
695 """);
696 scratch.file(
697 "test/pkg/BUILD",
698 """
699 alias(
700 name = "two",
701 actual = "//test:three",
702 )
703 """);
704
705 OptionsParsingException e =
706 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//test:one=one"));
707
708 assertThat(e)
709 .hasMessageThat()
710 .isEqualTo("Unrecognized option: //test:one -> //test/pkg:two -> //test:three");
711 }
juliexxiacb9b2af2018-11-30 17:21:22 -0800712}