blob: 42ef9a8f24b804656592b8c6b86248a553e1d64b [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;
21import com.google.devtools.build.lib.runtime.StarlarkOptionsParser;
laurentlbc67c5702020-07-30 09:25:45 -070022import com.google.devtools.build.lib.starlark.util.StarlarkOptionsTestCase;
Julie Xia69d4ace2020-05-29 11:25:25 -070023import com.google.devtools.build.lib.util.Pair;
juliexxiacb9b2af2018-11-30 17:21:22 -080024import com.google.devtools.common.options.OptionsParsingException;
25import com.google.devtools.common.options.OptionsParsingResult;
adonovan3ed7ed52020-09-30 12:03:28 -070026import net.starlark.java.eval.StarlarkInt;
juliexxiacb9b2af2018-11-30 17:21:22 -080027import org.junit.Test;
28import org.junit.runner.RunWith;
29import org.junit.runners.JUnit4;
30
31/** Unit test for the {@code StarlarkOptionsParser}. */
32@RunWith(JUnit4.class)
jcater741926e2019-12-02 06:50:08 -080033public class StarlarkOptionsParsingTest extends StarlarkOptionsTestCase {
juliexxiacb9b2af2018-11-30 17:21:22 -080034
35 // test --flag=value
36 @Test
37 public void testFlagEqualsValueForm() throws Exception {
38 writeBasicIntFlag();
39
40 OptionsParsingResult result = parseStarlarkOptions("--//test:my_int_setting=666");
41
42 assertThat(result.getStarlarkOptions()).hasSize(1);
adonovan3ed7ed52020-09-30 12:03:28 -070043 assertThat(result.getStarlarkOptions().get("//test:my_int_setting"))
44 .isEqualTo(StarlarkInt.of(666));
juliexxiacb9b2af2018-11-30 17:21:22 -080045 assertThat(result.getResidue()).isEmpty();
46 }
47
John Millikinfff73092019-10-22 15:12:32 -070048 // test --@workspace//flag=value
49 @Test
50 public void testFlagNameWithWorkspace() throws Exception {
51 writeBasicIntFlag();
52 rewriteWorkspace("workspace(name = 'starlark_options_test')");
53
54 OptionsParsingResult result =
55 parseStarlarkOptions("--@starlark_options_test//test:my_int_setting=666");
56
57 assertThat(result.getStarlarkOptions()).hasSize(1);
58 assertThat(result.getStarlarkOptions().get("@starlark_options_test//test:my_int_setting"))
adonovan3ed7ed52020-09-30 12:03:28 -070059 .isEqualTo(StarlarkInt.of(666));
John Millikinfff73092019-10-22 15:12:32 -070060 assertThat(result.getResidue()).isEmpty();
61 }
62
juliexxiacb9b2af2018-11-30 17:21:22 -080063 // test --fake_flag=value
64 @Test
65 public void testBadFlag_equalsForm() throws Exception {
66 scratch.file("test/BUILD");
67 reporter.removeHandler(failFastHandler);
68
69 OptionsParsingException e =
70 assertThrows(
71 OptionsParsingException.class,
72 () -> parseStarlarkOptions("--//fake_flag=blahblahblah"));
73
74 assertThat(e).hasMessageThat().contains("Error loading option //fake_flag");
Googlerddb9b9a2020-06-26 12:50:43 -070075 assertThat(e.getInvalidArgument()).isEqualTo("//fake_flag");
juliexxiacb9b2af2018-11-30 17:21:22 -080076 }
77
juliexxiacb9b2af2018-11-30 17:21:22 -080078 // test --fake_flag
79 @Test
80 public void testBadFlag_boolForm() throws Exception {
81 scratch.file("test/BUILD");
82 reporter.removeHandler(failFastHandler);
83
84 OptionsParsingException e =
85 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//fake_flag"));
86
87 assertThat(e).hasMessageThat().contains("Error loading option //fake_flag");
Googlerddb9b9a2020-06-26 12:50:43 -070088 assertThat(e.getInvalidArgument()).isEqualTo("//fake_flag");
juliexxiacb9b2af2018-11-30 17:21:22 -080089 }
90
juliexxiacb9b2af2018-11-30 17:21:22 -080091 @Test
gregceae07b7c2020-12-07 11:00:04 -080092 public void testBadFlag_keepGoing() throws Exception {
93 optionsParser.parse("--keep_going");
94 scratch.file("test/BUILD");
95 reporter.removeHandler(failFastHandler);
96
97 OptionsParsingException e =
98 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//fake_flag"));
99
100 assertThat(e).hasMessageThat().contains("Error loading option //fake_flag");
101 assertThat(e.getInvalidArgument()).isEqualTo("//fake_flag");
102 }
103
104 @Test
juliexxiacb9b2af2018-11-30 17:21:22 -0800105 public void testSingleDash_notAllowed() throws Exception {
juliexxiacb9b2af2018-11-30 17:21:22 -0800106 writeBasicIntFlag();
107
108 OptionsParsingResult result = parseStarlarkOptions("-//test:my_int_setting=666");
109
110 assertThat(result.getStarlarkOptions()).isEmpty();
111 assertThat(result.getResidue()).containsExactly("-//test:my_int_setting=666");
112 }
113
114 // test --non_flag_setting=value
115 @Test
116 public void testNonFlagParsing() throws Exception {
juliexxiacb9b2af2018-11-30 17:21:22 -0800117 scratch.file(
118 "test/build_setting.bzl",
119 "def _build_setting_impl(ctx):",
120 " return []",
121 "int_flag = rule(",
122 " implementation = _build_setting_impl,",
123 " build_setting = config.int(flag=False)",
124 ")");
125 scratch.file(
126 "test/BUILD",
127 "load('//test:build_setting.bzl', 'int_flag')",
128 "int_flag(name = 'my_int_setting', build_setting_default = 42)");
129
130 OptionsParsingException e =
131 assertThrows(
132 OptionsParsingException.class,
133 () -> parseStarlarkOptions("--//test:my_int_setting=666"));
134
135 assertThat(e).hasMessageThat().isEqualTo("Unrecognized option: //test:my_int_setting=666");
136 }
137
juliexxiacb9b2af2018-11-30 17:21:22 -0800138 // test --bool_flag
139 @Test
140 public void testBooleanFlag() throws Exception {
141 writeBasicBoolFlag();
142
juliexxiad2860842019-06-05 12:30:35 -0700143 OptionsParsingResult result = parseStarlarkOptions("--//test:my_bool_setting=false");
juliexxiacb9b2af2018-11-30 17:21:22 -0800144
145 assertThat(result.getStarlarkOptions()).hasSize(1);
juliexxiad2860842019-06-05 12:30:35 -0700146 assertThat(result.getStarlarkOptions().get("//test:my_bool_setting")).isEqualTo(false);
juliexxiacb9b2af2018-11-30 17:21:22 -0800147 assertThat(result.getResidue()).isEmpty();
148 }
149
150 // test --nobool_flag
151 @Test
152 public void testNoPrefixedBooleanFlag() throws Exception {
153 writeBasicBoolFlag();
154
155 OptionsParsingResult result = parseStarlarkOptions("--no//test:my_bool_setting");
156
157 assertThat(result.getStarlarkOptions()).hasSize(1);
158 assertThat(result.getStarlarkOptions().get("//test:my_bool_setting")).isEqualTo(false);
159 assertThat(result.getResidue()).isEmpty();
160 }
161
162 // test --noint_flag
163 @Test
164 public void testNoPrefixedNonBooleanFlag() throws Exception {
165 writeBasicIntFlag();
166
167 OptionsParsingException e =
168 assertThrows(
169 OptionsParsingException.class, () -> parseStarlarkOptions("--no//test:my_int_setting"));
170
171 assertThat(e)
172 .hasMessageThat()
173 .isEqualTo("Illegal use of 'no' prefix on non-boolean option: //test:my_int_setting");
174 }
175
176 // test --int_flag
177 @Test
178 public void testFlagWithoutValue() throws Exception {
179 writeBasicIntFlag();
180
181 OptionsParsingException e =
182 assertThrows(
183 OptionsParsingException.class, () -> parseStarlarkOptions("--//test:my_int_setting"));
184
185 assertThat(e).hasMessageThat().isEqualTo("Expected value after --//test:my_int_setting");
186 }
187
188 // test --flag --flag
189 @Test
190 public void testRepeatFlagLastOneWins() throws Exception {
191 writeBasicIntFlag();
192
193 OptionsParsingResult result =
194 parseStarlarkOptions("--//test:my_int_setting=4 --//test:my_int_setting=7");
195
196 assertThat(result.getStarlarkOptions()).hasSize(1);
adonovan3ed7ed52020-09-30 12:03:28 -0700197 assertThat(result.getStarlarkOptions().get("//test:my_int_setting"))
198 .isEqualTo(StarlarkInt.of(7));
juliexxiacb9b2af2018-11-30 17:21:22 -0800199 assertThat(result.getResidue()).isEmpty();
200 }
201
202 // test --flagA=valueA --flagB=valueB
203 @Test
204 public void testMultipleFlags() throws Exception {
juliexxiacb9b2af2018-11-30 17:21:22 -0800205 scratch.file(
206 "test/build_setting.bzl",
207 "def _build_setting_impl(ctx):",
208 " return []",
209 "int_flag = rule(",
210 " implementation = _build_setting_impl,",
211 " build_setting = config.int(flag=True)",
212 ")");
213 scratch.file(
214 "test/BUILD",
215 "load('//test:build_setting.bzl', 'int_flag')",
216 "int_flag(name = 'my_int_setting', build_setting_default = 42)",
217 "int_flag(name = 'my_other_int_setting', build_setting_default = 77)");
218
219 OptionsParsingResult result =
220 parseStarlarkOptions("--//test:my_int_setting=0 --//test:my_other_int_setting=0");
221
222 assertThat(result.getResidue()).isEmpty();
223 assertThat(result.getStarlarkOptions()).hasSize(2);
adonovan3ed7ed52020-09-30 12:03:28 -0700224 assertThat(result.getStarlarkOptions().get("//test:my_int_setting"))
225 .isEqualTo(StarlarkInt.of(0));
226 assertThat(result.getStarlarkOptions().get("//test:my_other_int_setting"))
227 .isEqualTo(StarlarkInt.of(0));
juliexxiacb9b2af2018-11-30 17:21:22 -0800228 }
229
230 // test --non_build_setting
231 @Test
232 public void testNonBuildSetting() throws Exception {
233 scratch.file(
234 "test/rules.bzl",
235 "def _impl(ctx):",
236 " return []",
237 "my_rule = rule(",
238 " implementation = _impl,",
239 ")");
240 scratch.file("test/BUILD", "load('//test:rules.bzl', 'my_rule')", "my_rule(name = 'my_rule')");
241 OptionsParsingException e =
242 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//test:my_rule"));
243 assertThat(e).hasMessageThat().isEqualTo("Unrecognized option: //test:my_rule");
244 }
245
246 // test --non_rule_configured_target
247 @Test
248 public void testNonRuleConfiguredTarget() throws Exception {
249 scratch.file(
250 "test/BUILD",
251 "genrule(",
252 " name = 'my_gen',",
253 " srcs = ['x.in'],",
254 " outs = ['x.cc'],",
255 " cmd = '$(locations :tool) $< >$@',",
256 " tools = [':tool'],",
257 ")",
258 "cc_library(name = 'tool-dep')");
259 OptionsParsingException e =
260 assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//test:x.in"));
261 assertThat(e).hasMessageThat().isEqualTo("Unrecognized option: //test:x.in");
262 }
263
264 // test --int_flag=non_int_value
265 @Test
266 public void testWrongValueType_int() throws Exception {
267 writeBasicIntFlag();
268
269 OptionsParsingException e =
270 assertThrows(
271 OptionsParsingException.class,
272 () -> parseStarlarkOptions("--//test:my_int_setting=woohoo"));
273
274 assertThat(e)
275 .hasMessageThat()
276 .isEqualTo("While parsing option //test:my_int_setting=woohoo: 'woohoo' is not a int");
277 }
278
279 // test --bool_flag=non_bool_value
280 @Test
281 public void testWrongValueType_bool() throws Exception {
282 writeBasicBoolFlag();
283
284 OptionsParsingException e =
285 assertThrows(
286 OptionsParsingException.class,
287 () -> parseStarlarkOptions("--//test:my_bool_setting=woohoo"));
288
289 assertThat(e)
290 .hasMessageThat()
291 .isEqualTo("While parsing option //test:my_bool_setting=woohoo: 'woohoo' is not a boolean");
292 }
juliexxiad2860842019-06-05 12:30:35 -0700293
294 // test --int-flag=same value as default
295 @Test
296 public void testDontStoreDefaultValue() throws Exception {
297 // build_setting_default = 42
298 writeBasicIntFlag();
299
300 OptionsParsingResult result = parseStarlarkOptions("--//test:my_int_setting=42");
301
302 assertThat(result.getStarlarkOptions()).isEmpty();
303 }
schmitt8fd43cf2019-11-19 15:49:27 -0800304
305 @Test
306 public void testOptionsAreParsedWithBuildTestsOnly() throws Exception {
307 writeBasicIntFlag();
308 optionsParser.parse("--build_tests_only");
309
310 OptionsParsingResult result = parseStarlarkOptions("--//test:my_int_setting=15");
311
adonovan3ed7ed52020-09-30 12:03:28 -0700312 assertThat(result.getStarlarkOptions().get("//test:my_int_setting"))
313 .isEqualTo(StarlarkInt.of(15));
schmitt8fd43cf2019-11-19 15:49:27 -0800314 }
Julie Xia69d4ace2020-05-29 11:25:25 -0700315
316 @Test
317 public void testRemoveStarlarkOptionsWorks() throws Exception {
318 Pair<ImmutableList<String>, ImmutableList<String>> residueAndStarlarkOptions =
319 StarlarkOptionsParser.removeStarlarkOptions(
320 ImmutableList.of(
321 "--//local/starlark/option",
322 "--@some_repo//external/starlark/option",
323 "--@//main/repo/option",
324 "some-random-residue",
325 "--mangled//external/starlark/option"));
326 assertThat(residueAndStarlarkOptions.getFirst())
327 .containsExactly(
328 "--//local/starlark/option",
329 "--@some_repo//external/starlark/option",
330 "--@//main/repo/option");
331 assertThat(residueAndStarlarkOptions.getSecond())
332 .containsExactly("some-random-residue", "--mangled//external/starlark/option");
333 }
juliexxiacb9b2af2018-11-30 17:21:22 -0800334}