just playing with tangled
at ig/vimdiffwarn 465 lines 15 kB view raw
1// Copyright 2022 The Jujutsu Authors 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// https://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 15use crate::common::TestEnvironment; 16 17#[test] 18fn test_alias_basic() { 19 let test_env = TestEnvironment::default(); 20 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 21 let work_dir = test_env.work_dir("repo"); 22 23 test_env.add_config(r#"aliases.bk = ["log", "-r", "@", "-T", "bookmarks"]"#); 24 work_dir 25 .run_jj(["bookmark", "create", "my-bookmark", "-r", "@"]) 26 .success(); 27 let output = work_dir.run_jj(["bk"]); 28 insta::assert_snapshot!(output, @r" 29 @ my-bookmark 30 31 ~ 32 [EOF] 33 "); 34} 35 36#[test] 37fn test_alias_bad_name() { 38 let test_env = TestEnvironment::default(); 39 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 40 let work_dir = test_env.work_dir("repo"); 41 42 let output = work_dir.run_jj(["foo."]); 43 insta::assert_snapshot!(output, @r" 44 ------- stderr ------- 45 error: unrecognized subcommand 'foo.' 46 47 Usage: jj [OPTIONS] <COMMAND> 48 49 For more information, try '--help'. 50 [EOF] 51 [exit status: 2] 52 "); 53} 54 55#[test] 56fn test_alias_calls_empty_command() { 57 let test_env = TestEnvironment::default(); 58 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 59 let work_dir = test_env.work_dir("repo"); 60 61 test_env.add_config( 62 r#" 63 aliases.empty = [] 64 aliases.empty_command_with_opts = ["--no-pager"] 65 "#, 66 ); 67 68 let output = work_dir.run_jj(["empty"]); 69 insta::assert_snapshot!( 70 output.normalize_stderr_with(|s| s.split_inclusive('\n').take(3).collect()), @r" 71 ------- stderr ------- 72 Jujutsu (An experimental VCS) 73 74 Usage: jj [OPTIONS] <COMMAND> 75 [EOF] 76 [exit status: 2] 77 "); 78 let output = work_dir.run_jj(["empty", "--no-pager"]); 79 insta::assert_snapshot!( 80 output.normalize_stderr_with(|s| s.split_inclusive('\n').take(1).collect()), @r" 81 ------- stderr ------- 82 error: 'jj' requires a subcommand but one was not provided 83 [EOF] 84 [exit status: 2] 85 "); 86 let output = work_dir.run_jj(["empty_command_with_opts"]); 87 insta::assert_snapshot!( 88 output.normalize_stderr_with(|s| s.split_inclusive('\n').take(1).collect()), @r" 89 ------- stderr ------- 90 error: 'jj' requires a subcommand but one was not provided 91 [EOF] 92 [exit status: 2] 93 "); 94} 95 96#[test] 97fn test_alias_calls_unknown_command() { 98 let test_env = TestEnvironment::default(); 99 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 100 let work_dir = test_env.work_dir("repo"); 101 102 test_env.add_config(r#"aliases.foo = ["nonexistent"]"#); 103 let output = work_dir.run_jj(["foo"]); 104 insta::assert_snapshot!(output, @r" 105 ------- stderr ------- 106 error: unrecognized subcommand 'nonexistent' 107 108 tip: a similar subcommand exists: 'next' 109 110 Usage: jj [OPTIONS] <COMMAND> 111 112 For more information, try '--help'. 113 [EOF] 114 [exit status: 2] 115 "); 116} 117 118#[test] 119fn test_alias_calls_command_with_invalid_option() { 120 let test_env = TestEnvironment::default(); 121 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 122 let work_dir = test_env.work_dir("repo"); 123 124 test_env.add_config(r#"aliases.foo = ["log", "--nonexistent"]"#); 125 let output = work_dir.run_jj(["foo"]); 126 insta::assert_snapshot!(output, @r" 127 ------- stderr ------- 128 error: unexpected argument '--nonexistent' found 129 130 tip: to pass '--nonexistent' as a value, use '-- --nonexistent' 131 132 Usage: jj log [OPTIONS] [FILESETS]... 133 134 For more information, try '--help'. 135 [EOF] 136 [exit status: 2] 137 "); 138} 139 140#[test] 141fn test_alias_calls_help() { 142 let test_env = TestEnvironment::default(); 143 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 144 let work_dir = test_env.work_dir("repo"); 145 test_env.add_config(r#"aliases.h = ["--help"]"#); 146 let output = work_dir.run_jj(&["h"]); 147 insta::assert_snapshot!( 148 output.normalize_stdout_with(|s| s.split_inclusive('\n').take(7).collect()), @r" 149 Jujutsu (An experimental VCS) 150 151 To get started, see the tutorial [`jj help -k tutorial`]. 152 153 [`jj help -k tutorial`]: https://jj-vcs.github.io/jj/latest/tutorial/ 154 155 Usage: jj [OPTIONS] <COMMAND> 156 [EOF] 157 "); 158} 159 160#[test] 161fn test_alias_cannot_override_builtin() { 162 let test_env = TestEnvironment::default(); 163 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 164 let work_dir = test_env.work_dir("repo"); 165 166 test_env.add_config(r#"aliases.log = ["rebase"]"#); 167 // Alias should give a warning 168 let output = work_dir.run_jj(["log", "-r", "root()"]); 169 insta::assert_snapshot!(output, @r" 170 ◆ zzzzzzzz root() 00000000 171 [EOF] 172 ------- stderr ------- 173 Warning: Cannot define an alias that overrides the built-in command 'log' 174 [EOF] 175 "); 176} 177 178#[test] 179fn test_alias_recursive() { 180 let test_env = TestEnvironment::default(); 181 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 182 let work_dir = test_env.work_dir("repo"); 183 184 test_env.add_config( 185 r#"[aliases] 186 foo = ["foo"] 187 bar = ["baz"] 188 baz = ["bar"] 189 "#, 190 ); 191 // Alias should not cause infinite recursion or hang 192 let output = work_dir.run_jj(["foo"]); 193 insta::assert_snapshot!(output, @r" 194 ------- stderr ------- 195 Error: Recursive alias definition involving `foo` 196 [EOF] 197 [exit status: 1] 198 "); 199 // Also test with mutual recursion 200 let output = work_dir.run_jj(["bar"]); 201 insta::assert_snapshot!(output, @r" 202 ------- stderr ------- 203 Error: Recursive alias definition involving `bar` 204 [EOF] 205 [exit status: 1] 206 "); 207} 208 209#[test] 210fn test_alias_global_args_before_and_after() { 211 let test_env = TestEnvironment::default(); 212 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 213 let work_dir = test_env.work_dir("repo"); 214 test_env.add_config(r#"aliases.l = ["log", "-T", "commit_id", "-r", "all()"]"#); 215 // Test the setup 216 let output = work_dir.run_jj(["l"]); 217 insta::assert_snapshot!(output, @r" 218 @ 230dd059e1b059aefc0da06a2e5a7dbf22362f22 219 ◆ 0000000000000000000000000000000000000000 220 [EOF] 221 "); 222 223 // Can pass global args before 224 let output = work_dir.run_jj(["l", "--at-op", "@-"]); 225 insta::assert_snapshot!(output, @r" 226 ◆ 0000000000000000000000000000000000000000 227 [EOF] 228 "); 229 // Can pass global args after 230 let output = work_dir.run_jj(["--at-op", "@-", "l"]); 231 insta::assert_snapshot!(output, @r" 232 ◆ 0000000000000000000000000000000000000000 233 [EOF] 234 "); 235 // Test passing global args both before and after 236 let output = work_dir.run_jj(["--at-op", "abc123", "l", "--at-op", "@-"]); 237 insta::assert_snapshot!(output, @r" 238 ◆ 0000000000000000000000000000000000000000 239 [EOF] 240 "); 241 let output = work_dir.run_jj(["-R", "../nonexistent", "l", "-R", "."]); 242 insta::assert_snapshot!(output, @r" 243 @ 230dd059e1b059aefc0da06a2e5a7dbf22362f22 244 ◆ 0000000000000000000000000000000000000000 245 [EOF] 246 "); 247} 248 249#[test] 250fn test_alias_global_args_in_definition() { 251 let test_env = TestEnvironment::default(); 252 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 253 let work_dir = test_env.work_dir("repo"); 254 test_env.add_config( 255 r#"aliases.l = ["log", "-T", "commit_id", "--at-op", "@-", "-r", "all()", "--color=always"]"#, 256 ); 257 258 // The global argument in the alias is respected 259 let output = work_dir.run_jj(["l"]); 260 insta::assert_snapshot!(output, @r" 261 ◆ 0000000000000000000000000000000000000000 262 [EOF] 263 "); 264} 265 266#[test] 267fn test_alias_invalid_definition() { 268 let test_env = TestEnvironment::default(); 269 270 test_env.add_config( 271 r#"[aliases] 272 non-list = 5 273 non-string-list = [0] 274 "#, 275 ); 276 let output = test_env.run_jj_in(".", ["non-list"]); 277 insta::assert_snapshot!(output.normalize_backslash(), @r" 278 ------- stderr ------- 279 Config error: Invalid type or value for aliases.non-list 280 Caused by: invalid type: integer `5`, expected a sequence 281 282 Hint: Check the config file: $TEST_ENV/config/config0002.toml 283 For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. 284 [EOF] 285 [exit status: 1] 286 "); 287 let output = test_env.run_jj_in(".", ["non-string-list"]); 288 insta::assert_snapshot!(output, @r" 289 ------- stderr ------- 290 Config error: Invalid type or value for aliases.non-string-list 291 Caused by: invalid type: integer `0`, expected a string 292 293 Hint: Check the config file: $TEST_ENV/config/config0002.toml 294 For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. 295 [EOF] 296 [exit status: 1] 297 "); 298} 299 300#[test] 301fn test_alias_in_repo_config() { 302 let test_env = TestEnvironment::default(); 303 test_env.run_jj_in(".", ["git", "init", "repo1"]).success(); 304 let work_dir1 = test_env.work_dir("repo1"); 305 work_dir1.create_dir("sub"); 306 test_env.run_jj_in(".", ["git", "init", "repo2"]).success(); 307 let work_dir2 = test_env.work_dir("repo2"); 308 work_dir2.create_dir("sub"); 309 310 test_env.add_config(r#"aliases.l = ['log', '-r@', '--no-graph', '-T"user alias\n"']"#); 311 work_dir1.write_file( 312 ".jj/repo/config.toml", 313 r#"aliases.l = ['log', '-r@', '--no-graph', '-T"repo1 alias\n"']"#, 314 ); 315 316 // In repo1 sub directory, aliases can be loaded from the repo1 config. 317 let output = test_env.run_jj_in(work_dir1.root().join("sub"), ["l"]); 318 insta::assert_snapshot!(output, @r" 319 repo1 alias 320 [EOF] 321 "); 322 323 // In repo2 directory, no repo-local aliases exist. 324 let output = work_dir2.run_jj(["l"]); 325 insta::assert_snapshot!(output, @r" 326 user alias 327 [EOF] 328 "); 329 330 // Aliases can't be loaded from the -R path due to chicken and egg problem. 331 let output = work_dir2.run_jj(["l", "-R", work_dir1.root().to_str().unwrap()]); 332 insta::assert_snapshot!(output, @r" 333 user alias 334 [EOF] 335 ------- stderr ------- 336 Warning: Command aliases cannot be loaded from -R/--repository path or --config/--config-file arguments. 337 [EOF] 338 "); 339 340 // Aliases are loaded from the cwd-relative workspace even with -R. 341 let output = work_dir1.run_jj(["l", "-R", work_dir2.root().to_str().unwrap()]); 342 insta::assert_snapshot!(output, @r" 343 repo1 alias 344 [EOF] 345 ------- stderr ------- 346 Warning: Command aliases cannot be loaded from -R/--repository path or --config/--config-file arguments. 347 [EOF] 348 "); 349 350 // No warning if the expanded command is identical. 351 let output = work_dir1.run_jj(["file", "list", "-R", work_dir2.root().to_str().unwrap()]); 352 insta::assert_snapshot!(output, @""); 353 354 // Config loaded from the cwd-relative workspace shouldn't persist. It's 355 // used only for command arguments expansion. 356 let output = work_dir1.run_jj([ 357 "config", 358 "list", 359 "aliases", 360 "-R", 361 work_dir2.root().to_str().unwrap(), 362 ]); 363 insta::assert_snapshot!(output, @r#" 364 aliases.l = ['log', '-r@', '--no-graph', '-T"user alias\n"'] 365 [EOF] 366 "#); 367} 368 369#[test] 370fn test_alias_in_config_arg() { 371 let test_env = TestEnvironment::default(); 372 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 373 let work_dir = test_env.work_dir("repo"); 374 test_env.add_config(r#"aliases.l = ['log', '-r@', '--no-graph', '-T"user alias\n"']"#); 375 376 let output = work_dir.run_jj(["l"]); 377 insta::assert_snapshot!(output, @r" 378 user alias 379 [EOF] 380 "); 381 382 let alias_arg = r#"--config=aliases.l=['log', '-r@', '--no-graph', '-T"arg alias\n"']"#; 383 let output = work_dir.run_jj([alias_arg, "l"]); 384 insta::assert_snapshot!(output, @r" 385 user alias 386 [EOF] 387 ------- stderr ------- 388 Warning: Command aliases cannot be loaded from -R/--repository path or --config/--config-file arguments. 389 [EOF] 390 "); 391 // should print warning about aliases even if cli parsing fails 392 let alias_arg = r#"--config=aliases.this-command-not-exist=['log', '-r@', '--no-graph', '-T"arg alias\n"']"#; 393 let output = work_dir.run_jj([alias_arg, "this-command-not-exist"]); 394 insta::assert_snapshot!(output, @r" 395 ------- stderr ------- 396 Warning: Command aliases cannot be loaded from -R/--repository path or --config/--config-file arguments. 397 error: unrecognized subcommand 'this-command-not-exist' 398 399 Usage: jj [OPTIONS] <COMMAND> 400 401 For more information, try '--help'. 402 [EOF] 403 [exit status: 2] 404 "); 405} 406 407#[test] 408fn test_aliases_overriding_friendly_errors() { 409 let test_env = TestEnvironment::default(); 410 // Test with color 411 let output = test_env.run_jj_in(".", ["--color=always", "init", "repo"]); 412 insta::assert_snapshot!(output, @r#" 413 ------- stderr ------- 414 error: unrecognized subcommand 'init' 415 416 For more information, try '--help'. 417 Hint: You probably want `jj git init`. See also `jj help git`. 418 Hint: You can configure `aliases.init = ["git", "init"]` if you want `jj init` to work and always use the Git backend. 419 [EOF] 420 [exit status: 2] 421 "#); 422 423 let output = test_env.run_jj_in(".", ["init", "repo"]); 424 insta::assert_snapshot!(output, @r#" 425 ------- stderr ------- 426 error: unrecognized subcommand 'init' 427 428 For more information, try '--help'. 429 Hint: You probably want `jj git init`. See also `jj help git`. 430 Hint: You can configure `aliases.init = ["git", "init"]` if you want `jj init` to work and always use the Git backend. 431 [EOF] 432 [exit status: 2] 433 "#); 434 let output = test_env.run_jj_in(".", ["clone", "https://example.org/repo"]); 435 insta::assert_snapshot!(output, @r#" 436 ------- stderr ------- 437 error: unrecognized subcommand 'clone' 438 439 For more information, try '--help'. 440 Hint: You probably want `jj git clone`. See also `jj help git`. 441 Hint: You can configure `aliases.clone = ["git", "clone"]` if you want `jj clone` to work and always use the Git backend. 442 [EOF] 443 [exit status: 2] 444 "#); 445 let output = test_env.run_jj_in(".", ["init", "--help"]); 446 insta::assert_snapshot!(output, @r#" 447 ------- stderr ------- 448 error: unrecognized subcommand 'init' 449 450 For more information, try '--help'. 451 Hint: You probably want `jj git init`. See also `jj help git`. 452 Hint: You can configure `aliases.init = ["git", "init"]` if you want `jj init` to work and always use the Git backend. 453 [EOF] 454 [exit status: 2] 455 "#); 456 457 // Test that `init` can be overridden as an alias. (We use `jj config get` 458 // as a command with a predictable output) 459 test_env.add_config(r#"aliases.init=["config", "get", "user.name"]"#); 460 let output = test_env.run_jj_in(".", ["init"]); 461 insta::assert_snapshot!(output, @r" 462 Test User 463 [EOF] 464 "); 465}