juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 1 | // 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 | |
laurentlb | c67c570 | 2020-07-30 09:25:45 -0700 | [diff] [blame] | 15 | package com.google.devtools.build.lib.starlark; |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 16 | |
| 17 | import static com.google.common.truth.Truth.assertThat; |
michajlo | 660d17f | 2020-03-27 09:01:57 -0700 | [diff] [blame] | 18 | import static org.junit.Assert.assertThrows; |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 19 | |
Julie Xia | 69d4ace | 2020-05-29 11:25:25 -0700 | [diff] [blame] | 20 | import com.google.common.collect.ImmutableList; |
| 21 | import com.google.devtools.build.lib.runtime.StarlarkOptionsParser; |
laurentlb | c67c570 | 2020-07-30 09:25:45 -0700 | [diff] [blame] | 22 | import com.google.devtools.build.lib.starlark.util.StarlarkOptionsTestCase; |
Julie Xia | 69d4ace | 2020-05-29 11:25:25 -0700 | [diff] [blame] | 23 | import com.google.devtools.build.lib.util.Pair; |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 24 | import com.google.devtools.common.options.OptionsParsingException; |
| 25 | import com.google.devtools.common.options.OptionsParsingResult; |
adonovan | 3ed7ed5 | 2020-09-30 12:03:28 -0700 | [diff] [blame] | 26 | import net.starlark.java.eval.StarlarkInt; |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 27 | import org.junit.Test; |
| 28 | import org.junit.runner.RunWith; |
| 29 | import org.junit.runners.JUnit4; |
| 30 | |
| 31 | /** Unit test for the {@code StarlarkOptionsParser}. */ |
| 32 | @RunWith(JUnit4.class) |
jcater | 741926e | 2019-12-02 06:50:08 -0800 | [diff] [blame] | 33 | public class StarlarkOptionsParsingTest extends StarlarkOptionsTestCase { |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 34 | |
| 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); |
adonovan | 3ed7ed5 | 2020-09-30 12:03:28 -0700 | [diff] [blame] | 43 | assertThat(result.getStarlarkOptions().get("//test:my_int_setting")) |
| 44 | .isEqualTo(StarlarkInt.of(666)); |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 45 | assertThat(result.getResidue()).isEmpty(); |
| 46 | } |
| 47 | |
John Millikin | fff7309 | 2019-10-22 15:12:32 -0700 | [diff] [blame] | 48 | // 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")) |
adonovan | 3ed7ed5 | 2020-09-30 12:03:28 -0700 | [diff] [blame] | 59 | .isEqualTo(StarlarkInt.of(666)); |
John Millikin | fff7309 | 2019-10-22 15:12:32 -0700 | [diff] [blame] | 60 | assertThat(result.getResidue()).isEmpty(); |
| 61 | } |
| 62 | |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 63 | // 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"); |
Googler | ddb9b9a | 2020-06-26 12:50:43 -0700 | [diff] [blame] | 75 | assertThat(e.getInvalidArgument()).isEqualTo("//fake_flag"); |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 76 | } |
| 77 | |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 78 | // 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"); |
Googler | ddb9b9a | 2020-06-26 12:50:43 -0700 | [diff] [blame] | 88 | assertThat(e.getInvalidArgument()).isEqualTo("//fake_flag"); |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 89 | } |
| 90 | |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 91 | @Test |
gregce | ae07b7c | 2020-12-07 11:00:04 -0800 | [diff] [blame^] | 92 | 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 |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 105 | public void testSingleDash_notAllowed() throws Exception { |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 106 | 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 { |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 117 | 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 | |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 138 | // test --bool_flag |
| 139 | @Test |
| 140 | public void testBooleanFlag() throws Exception { |
| 141 | writeBasicBoolFlag(); |
| 142 | |
juliexxia | d286084 | 2019-06-05 12:30:35 -0700 | [diff] [blame] | 143 | OptionsParsingResult result = parseStarlarkOptions("--//test:my_bool_setting=false"); |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 144 | |
| 145 | assertThat(result.getStarlarkOptions()).hasSize(1); |
juliexxia | d286084 | 2019-06-05 12:30:35 -0700 | [diff] [blame] | 146 | assertThat(result.getStarlarkOptions().get("//test:my_bool_setting")).isEqualTo(false); |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 147 | 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); |
adonovan | 3ed7ed5 | 2020-09-30 12:03:28 -0700 | [diff] [blame] | 197 | assertThat(result.getStarlarkOptions().get("//test:my_int_setting")) |
| 198 | .isEqualTo(StarlarkInt.of(7)); |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 199 | assertThat(result.getResidue()).isEmpty(); |
| 200 | } |
| 201 | |
| 202 | // test --flagA=valueA --flagB=valueB |
| 203 | @Test |
| 204 | public void testMultipleFlags() throws Exception { |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 205 | 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); |
adonovan | 3ed7ed5 | 2020-09-30 12:03:28 -0700 | [diff] [blame] | 224 | 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)); |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 228 | } |
| 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 | } |
juliexxia | d286084 | 2019-06-05 12:30:35 -0700 | [diff] [blame] | 293 | |
| 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 | } |
schmitt | 8fd43cf | 2019-11-19 15:49:27 -0800 | [diff] [blame] | 304 | |
| 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 | |
adonovan | 3ed7ed5 | 2020-09-30 12:03:28 -0700 | [diff] [blame] | 312 | assertThat(result.getStarlarkOptions().get("//test:my_int_setting")) |
| 313 | .isEqualTo(StarlarkInt.of(15)); |
schmitt | 8fd43cf | 2019-11-19 15:49:27 -0800 | [diff] [blame] | 314 | } |
Julie Xia | 69d4ace | 2020-05-29 11:25:25 -0700 | [diff] [blame] | 315 | |
| 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 | } |
juliexxia | cb9b2af | 2018-11-30 17:21:22 -0800 | [diff] [blame] | 334 | } |