just playing with tangled
at ig/vimdiffwarn 1706 lines 50 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::to_toml_value; 16use crate::common::TestEnvironment; 17 18#[test] 19fn test_log_with_empty_revision() { 20 let test_env = TestEnvironment::default(); 21 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 22 let work_dir = test_env.work_dir("repo"); 23 24 let output = work_dir.run_jj(["log", "-r="]); 25 insta::assert_snapshot!(output, @r" 26 ------- stderr ------- 27 error: a value is required for '--revisions <REVSETS>' but none was supplied 28 29 For more information, try '--help'. 30 [EOF] 31 [exit status: 2] 32 "); 33} 34 35#[test] 36fn test_log_with_no_template() { 37 let test_env = TestEnvironment::default(); 38 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 39 let work_dir = test_env.work_dir("repo"); 40 41 let output = work_dir.run_jj(["log", "-T"]); 42 insta::assert_snapshot!(output, @r" 43 ------- stderr ------- 44 error: a value is required for '--template <TEMPLATE>' but none was supplied 45 46 For more information, try '--help'. 47 Hint: The following template aliases are defined: 48 - builtin_config_list 49 - builtin_config_list_detailed 50 - builtin_draft_commit_description 51 - builtin_log_comfortable 52 - builtin_log_compact 53 - builtin_log_compact_full_description 54 - builtin_log_detailed 55 - builtin_log_node 56 - builtin_log_node_ascii 57 - builtin_log_oneline 58 - builtin_op_log_comfortable 59 - builtin_op_log_compact 60 - builtin_op_log_node 61 - builtin_op_log_node_ascii 62 - builtin_op_log_oneline 63 - commit_summary_separator 64 - description_placeholder 65 - email_placeholder 66 - name_placeholder 67 [EOF] 68 [exit status: 2] 69 "); 70} 71 72#[test] 73fn test_log_with_or_without_diff() { 74 let test_env = TestEnvironment::default(); 75 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 76 let work_dir = test_env.work_dir("repo"); 77 78 work_dir.write_file("file1", "foo\n"); 79 work_dir.run_jj(["describe", "-m", "add a file"]).success(); 80 work_dir.run_jj(["new", "-m", "a new commit"]).success(); 81 work_dir.write_file("file1", "foo\nbar\n"); 82 83 let output = work_dir.run_jj(["log", "-T", "description"]); 84 insta::assert_snapshot!(output, @r" 85 @ a new commit 86 ○ add a file 87 88 [EOF] 89 "); 90 91 let output = work_dir.run_jj(["log", "-T", "description", "-p"]); 92 insta::assert_snapshot!(output, @r" 93 @ a new commit 94 │ Modified regular file file1: 95 │ 1 1: foo 96 │ 2: bar 97 ○ add a file 98 │ Added regular file file1: 99 │ 1: foo 100 101 [EOF] 102 "); 103 104 let output = work_dir.run_jj(["log", "-T", "description", "--no-graph"]); 105 insta::assert_snapshot!(output, @r" 106 a new commit 107 add a file 108 [EOF] 109 "); 110 111 // `-p` for default diff output, `-s` for summary 112 let output = work_dir.run_jj(["log", "-T", "description", "-p", "-s"]); 113 insta::assert_snapshot!(output, @r" 114 @ a new commit 115 │ M file1 116 │ Modified regular file file1: 117 │ 1 1: foo 118 │ 2: bar 119 ○ add a file 120 │ A file1 121 │ Added regular file file1: 122 │ 1: foo 123 124 [EOF] 125 "); 126 127 // `-s` for summary, `--git` for git diff (which implies `-p`) 128 let output = work_dir.run_jj(["log", "-T", "description", "-s", "--git"]); 129 insta::assert_snapshot!(output, @r" 130 @ a new commit 131 │ M file1 132 │ diff --git a/file1 b/file1 133 │ index 257cc5642c..3bd1f0e297 100644 134 │ --- a/file1 135 │ +++ b/file1 136 │ @@ -1,1 +1,2 @@ 137 │ foo 138 │ +bar 139 ○ add a file 140 │ A file1 141 │ diff --git a/file1 b/file1 142 │ new file mode 100644 143 │ index 0000000000..257cc5642c 144 │ --- /dev/null 145 │ +++ b/file1 146 │ @@ -0,0 +1,1 @@ 147 │ +foo 148 149 [EOF] 150 "); 151 152 // `-p` for default diff output, `--stat` for diff-stat 153 let output = work_dir.run_jj(["log", "-T", "description", "-p", "--stat"]); 154 insta::assert_snapshot!(output, @r" 155 @ a new commit 156 │ file1 | 1 + 157 │ 1 file changed, 1 insertion(+), 0 deletions(-) 158 │ Modified regular file file1: 159 │ 1 1: foo 160 │ 2: bar 161 ○ add a file 162 │ file1 | 1 + 163 │ 1 file changed, 1 insertion(+), 0 deletions(-) 164 │ Added regular file file1: 165 │ 1: foo 166 167 0 files changed, 0 insertions(+), 0 deletions(-) 168 [EOF] 169 "); 170 171 // `--stat` is short format, which should be printed first 172 let output = work_dir.run_jj(["log", "-T", "description", "--git", "--stat"]); 173 insta::assert_snapshot!(output, @r" 174 @ a new commit 175 │ file1 | 1 + 176 │ 1 file changed, 1 insertion(+), 0 deletions(-) 177 │ diff --git a/file1 b/file1 178 │ index 257cc5642c..3bd1f0e297 100644 179 │ --- a/file1 180 │ +++ b/file1 181 │ @@ -1,1 +1,2 @@ 182 │ foo 183 │ +bar 184 ○ add a file 185 │ file1 | 1 + 186 │ 1 file changed, 1 insertion(+), 0 deletions(-) 187 │ diff --git a/file1 b/file1 188 │ new file mode 100644 189 │ index 0000000000..257cc5642c 190 │ --- /dev/null 191 │ +++ b/file1 192 │ @@ -0,0 +1,1 @@ 193 │ +foo 194 195 0 files changed, 0 insertions(+), 0 deletions(-) 196 [EOF] 197 "); 198 199 // `-p` enables default "summary" output, so `-s` is noop 200 let output = work_dir.run_jj([ 201 "log", 202 "-T", 203 "description", 204 "-p", 205 "-s", 206 "--config=ui.diff.format=summary", 207 ]); 208 insta::assert_snapshot!(output, @r" 209 @ a new commit 210 │ M file1 211 ○ add a file 212 │ A file1 213 214 [EOF] 215 "); 216 217 // `-p` enables default "color-words" diff output, so `--color-words` is noop 218 let output = work_dir.run_jj(["log", "-T", "description", "-p", "--color-words"]); 219 insta::assert_snapshot!(output, @r" 220 @ a new commit 221 │ Modified regular file file1: 222 │ 1 1: foo 223 │ 2: bar 224 ○ add a file 225 │ Added regular file file1: 226 │ 1: foo 227 228 [EOF] 229 "); 230 231 // `--git` enables git diff, so `-p` is noop 232 let output = work_dir.run_jj(["log", "-T", "description", "--no-graph", "-p", "--git"]); 233 insta::assert_snapshot!(output, @r" 234 a new commit 235 diff --git a/file1 b/file1 236 index 257cc5642c..3bd1f0e297 100644 237 --- a/file1 238 +++ b/file1 239 @@ -1,1 +1,2 @@ 240 foo 241 +bar 242 add a file 243 diff --git a/file1 b/file1 244 new file mode 100644 245 index 0000000000..257cc5642c 246 --- /dev/null 247 +++ b/file1 248 @@ -0,0 +1,1 @@ 249 +foo 250 [EOF] 251 "); 252 253 // Cannot use both `--git` and `--color-words` 254 let output = work_dir.run_jj([ 255 "log", 256 "-T", 257 "description", 258 "--no-graph", 259 "-p", 260 "--git", 261 "--color-words", 262 ]); 263 insta::assert_snapshot!(output, @r" 264 ------- stderr ------- 265 error: the argument '--git' cannot be used with '--color-words' 266 267 Usage: jj log --template <TEMPLATE> --no-graph --patch --git [FILESETS]... 268 269 For more information, try '--help'. 270 [EOF] 271 [exit status: 2] 272 "); 273 274 // `-s` with or without graph 275 let output = work_dir.run_jj(["log", "-T", "description", "-s"]); 276 insta::assert_snapshot!(output, @r" 277 @ a new commit 278 │ M file1 279 ○ add a file 280 │ A file1 281 282 [EOF] 283 "); 284 let output = work_dir.run_jj(["log", "-T", "description", "--no-graph", "-s"]); 285 insta::assert_snapshot!(output, @r" 286 a new commit 287 M file1 288 add a file 289 A file1 290 [EOF] 291 "); 292 293 // `--git` implies `-p`, with or without graph 294 let output = work_dir.run_jj(["log", "-T", "description", "-r", "@", "--git"]); 295 insta::assert_snapshot!(output, @r" 296 @ a new commit 297 │ diff --git a/file1 b/file1 298 ~ index 257cc5642c..3bd1f0e297 100644 299 --- a/file1 300 +++ b/file1 301 @@ -1,1 +1,2 @@ 302 foo 303 +bar 304 [EOF] 305 "); 306 let output = work_dir.run_jj(["log", "-T", "description", "-r", "@", "--no-graph", "--git"]); 307 insta::assert_snapshot!(output, @r" 308 a new commit 309 diff --git a/file1 b/file1 310 index 257cc5642c..3bd1f0e297 100644 311 --- a/file1 312 +++ b/file1 313 @@ -1,1 +1,2 @@ 314 foo 315 +bar 316 [EOF] 317 "); 318 319 // `--color-words` implies `-p`, with or without graph 320 let output = work_dir.run_jj(["log", "-T", "description", "-r", "@", "--color-words"]); 321 insta::assert_snapshot!(output, @r" 322 @ a new commit 323 │ Modified regular file file1: 324 ~ 1 1: foo 325 2: bar 326 [EOF] 327 "); 328 let output = work_dir.run_jj([ 329 "log", 330 "-T", 331 "description", 332 "-r", 333 "@", 334 "--no-graph", 335 "--color-words", 336 ]); 337 insta::assert_snapshot!(output, @r" 338 a new commit 339 Modified regular file file1: 340 1 1: foo 341 2: bar 342 [EOF] 343 "); 344} 345 346#[test] 347fn test_log_null_terminate_multiline_descriptions() { 348 let test_env = TestEnvironment::default(); 349 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 350 let work_dir = test_env.work_dir("repo"); 351 352 work_dir 353 .run_jj(["commit", "-m", "commit 1 line 1", "-m", "commit 1 line 2"]) 354 .success(); 355 work_dir 356 .run_jj(["commit", "-m", "commit 2 line 1", "-m", "commit 2 line 2"]) 357 .success(); 358 work_dir 359 .run_jj(["describe", "-m", "commit 3 line 1", "-m", "commit 3 line 2"]) 360 .success(); 361 362 let output = work_dir 363 .run_jj([ 364 "log", 365 "-r", 366 "~root()", 367 "-T", 368 r#"description ++ "\0""#, 369 "--no-graph", 370 ]) 371 .success(); 372 insta::assert_debug_snapshot!( 373 output.stdout.normalized(), 374 @r#""commit 3 line 1\n\ncommit 3 line 2\n\0commit 2 line 1\n\ncommit 2 line 2\n\0commit 1 line 1\n\ncommit 1 line 2\n\0""# 375 ); 376} 377 378#[test] 379fn test_log_shortest_accessors() { 380 let test_env = TestEnvironment::default(); 381 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 382 let work_dir = test_env.work_dir("repo"); 383 let render = |rev, template| work_dir.run_jj(["log", "--no-graph", "-r", rev, "-T", template]); 384 test_env.add_config( 385 r#" 386 [template-aliases] 387 'format_id(id)' = 'id.shortest(12).prefix() ++ "[" ++ id.shortest(12).rest() ++ "]"' 388 "#, 389 ); 390 391 work_dir.write_file("file", "original file\n"); 392 work_dir.run_jj(["describe", "-m", "initial"]).success(); 393 work_dir 394 .run_jj(["bookmark", "c", "-r@", "original"]) 395 .success(); 396 insta::assert_snapshot!( 397 render("original", r#"format_id(change_id) ++ " " ++ format_id(commit_id)"#), 398 @"q[pvuntsmwlqt] e[0e22b9fae75][EOF]"); 399 400 // Create a chain of 10 commits 401 for i in 1..10 { 402 work_dir 403 .run_jj(["new", "-m", &format!("commit{i}")]) 404 .success(); 405 work_dir.write_file("file", format!("file {i}\n")); 406 } 407 // Create 2^3 duplicates of the chain 408 for _ in 0..3 { 409 work_dir 410 .run_jj(["duplicate", "description(commit)"]) 411 .success(); 412 } 413 414 insta::assert_snapshot!( 415 render("original", r#"format_id(change_id) ++ " " ++ format_id(commit_id)"#), 416 @"qpv[untsmwlqt] e0[e22b9fae75][EOF]"); 417 418 insta::assert_snapshot!( 419 render("::@", r#"change_id.shortest() ++ " " ++ commit_id.shortest() ++ "\n""#), @r" 420 wq ed 421 km ef3 422 kp af 423 zn 23 424 yo b87 425 vr 1e 426 yq 34 427 ro cc 428 mz 1b 429 qpv e0 430 zzz 00 431 [EOF] 432 "); 433 434 insta::assert_snapshot!( 435 render("::@", r#"format_id(change_id) ++ " " ++ format_id(commit_id) ++ "\n""#), @r" 436 wq[nwkozpkust] ed[e204633421] 437 km[kuslswpqwq] ef3[d013266cd] 438 kp[qxywonksrl] af[95b841712d] 439 zn[kkpsqqskkl] 23[c1103d3427] 440 yo[stqsxwqrlt] b87[aa9b24921] 441 vr[uxwmqvtpmx] 1e[a31a205ce9] 442 yq[osqzytrlsw] 34[befb94f4eb] 443 ro[yxmykxtrkr] cc[0c127948ef] 444 mz[vwutvlkqwt] 1b[7b715afc3f] 445 qpv[untsmwlqt] e0[e22b9fae75] 446 zzz[zzzzzzzzz] 00[0000000000] 447 [EOF] 448 "); 449 450 // Can get shorter prefixes in configured revset 451 test_env.add_config(r#"revsets.short-prefixes = "(@----)::""#); 452 insta::assert_snapshot!( 453 render("::@", r#"format_id(change_id) ++ " " ++ format_id(commit_id) ++ "\n""#), @r" 454 w[qnwkozpkust] ed[e204633421] 455 km[kuslswpqwq] ef[3d013266cd] 456 kp[qxywonksrl] a[f95b841712d] 457 z[nkkpsqqskkl] 2[3c1103d3427] 458 y[ostqsxwqrlt] b[87aa9b24921] 459 vr[uxwmqvtpmx] 1e[a31a205ce9] 460 yq[osqzytrlsw] 34[befb94f4eb] 461 ro[yxmykxtrkr] cc[0c127948ef] 462 mz[vwutvlkqwt] 1b[7b715afc3f] 463 qpv[untsmwlqt] e0[e22b9fae75] 464 zzz[zzzzzzzzz] 00[0000000000] 465 [EOF] 466 "); 467 468 // Can disable short prefixes by setting to empty string 469 test_env.add_config(r#"revsets.short-prefixes = """#); 470 insta::assert_snapshot!( 471 render("::@", r#"format_id(change_id) ++ " " ++ format_id(commit_id) ++ "\n""#), @r" 472 wq[nwkozpkust] ed[e204633421] 473 km[kuslswpqwq] ef3[d013266cd] 474 kp[qxywonksrl] af[95b841712d] 475 zn[kkpsqqskkl] 23c[1103d3427] 476 yo[stqsxwqrlt] b87[aa9b24921] 477 vr[uxwmqvtpmx] 1e[a31a205ce9] 478 yq[osqzytrlsw] 34[befb94f4eb] 479 ro[yxmykxtrkr] cc[0c127948ef] 480 mz[vwutvlkqwt] 1b[7b715afc3f] 481 qpv[untsmwlqt] e0[e22b9fae75] 482 zzz[zzzzzzzzz] 00[0000000000] 483 [EOF] 484 "); 485} 486 487#[test] 488fn test_log_bad_short_prefixes() { 489 let test_env = TestEnvironment::default(); 490 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 491 let work_dir = test_env.work_dir("repo"); 492 493 // Suppress warning in the commit summary template 494 test_env.add_config("template-aliases.'format_short_id(id)' = 'id.short(8)'"); 495 496 // Error on bad config of short prefixes 497 test_env.add_config(r#"revsets.short-prefixes = "!nval!d""#); 498 let output = work_dir.run_jj(["status"]); 499 insta::assert_snapshot!(output, @r" 500 ------- stderr ------- 501 Config error: Invalid `revsets.short-prefixes` 502 Caused by: --> 1:1 503 | 504 1 | !nval!d 505 | ^--- 506 | 507 = expected <strict_identifier> or <expression> 508 For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. 509 [EOF] 510 [exit status: 1] 511 "); 512 513 // Warn on resolution of short prefixes 514 test_env.add_config("revsets.short-prefixes = 'missing'"); 515 let output = work_dir.run_jj(["log", "-Tcommit_id.shortest()"]); 516 insta::assert_snapshot!(output, @r" 517 @ 2 518 ◆ 0 519 [EOF] 520 ------- stderr ------- 521 Warning: In template expression 522 --> 1:11 523 | 524 1 | commit_id.shortest() 525 | ^------^ 526 | 527 = Failed to load short-prefixes index 528 Failed to resolve short-prefixes disambiguation revset 529 Revision `missing` doesn't exist 530 [EOF] 531 "); 532 533 // Error on resolution of short prefixes 534 test_env.add_config("revsets.short-prefixes = 'missing'"); 535 let output = work_dir.run_jj(["log", "-r0"]); 536 insta::assert_snapshot!(output, @r" 537 ------- stderr ------- 538 Error: Failed to resolve short-prefixes disambiguation revset 539 Caused by: Revision `missing` doesn't exist 540 [EOF] 541 [exit status: 1] 542 "); 543} 544 545#[test] 546fn test_log_prefix_highlight_styled() { 547 let test_env = TestEnvironment::default(); 548 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 549 let work_dir = test_env.work_dir("repo"); 550 551 fn prefix_format(len: Option<usize>) -> String { 552 format!( 553 r###" 554 separate(" ", 555 "Change", 556 change_id.shortest({0}), 557 description.first_line(), 558 commit_id.shortest({0}), 559 bookmarks, 560 ) 561 "###, 562 len.map(|l| l.to_string()).unwrap_or_default() 563 ) 564 } 565 566 work_dir.write_file("file", "original file\n"); 567 work_dir.run_jj(["describe", "-m", "initial"]).success(); 568 work_dir 569 .run_jj(["bookmark", "c", "-r@", "original"]) 570 .success(); 571 insta::assert_snapshot!( 572 work_dir.run_jj(["log", "-r", "original", "-T", &prefix_format(Some(12))]), @r" 573 @ Change qpvuntsmwlqt initial e0e22b9fae75 original 574 575 ~ 576 [EOF] 577 "); 578 579 // Create a chain of 10 commits 580 for i in 1..10 { 581 work_dir 582 .run_jj(["new", "-m", &format!("commit{i}")]) 583 .success(); 584 work_dir.write_file("file", format!("file {i}\n")); 585 } 586 // Create 2^3 duplicates of the chain 587 for _ in 0..3 { 588 work_dir 589 .run_jj(["duplicate", "description(commit)"]) 590 .success(); 591 } 592 593 insta::assert_snapshot!( 594 work_dir.run_jj(["log", "-r", "original", "-T", &prefix_format(Some(12))]), @r" 595 ○ Change qpvuntsmwlqt initial e0e22b9fae75 original 596 597 ~ 598 [EOF] 599 "); 600 let output = work_dir.run_jj([ 601 "--color=always", 602 "log", 603 "-r", 604 "@-----------..@", 605 "-T", 606 &prefix_format(Some(12)), 607 ]); 608 insta::assert_snapshot!(output, @r" 609 @ Change wqnwkozpkust commit9 ede204633421 610 ○ Change kmkuslswpqwq commit8 ef3d013266cd 611 ○ Change kpqxywonksrl commit7 af95b841712d 612 ○ Change znkkpsqqskkl commit6 23c1103d3427 613 ○ Change yostqsxwqrlt commit5 b87aa9b24921 614 ○ Change vruxwmqvtpmx commit4 1ea31a205ce9 615 ○ Change yqosqzytrlsw commit3 34befb94f4eb 616 ○ Change royxmykxtrkr commit2 cc0c127948ef 617 ○ Change mzvwutvlkqwt commit1 1b7b715afc3f 618 ○ Change qpvuntsmwlqt initial e0e22b9fae75 original 619 ◆ Change zzzzzzzzzzzz 000000000000 620 [EOF] 621 "); 622 let output = work_dir.run_jj([ 623 "--color=always", 624 "log", 625 "-r", 626 "@-----------..@", 627 "-T", 628 &prefix_format(Some(3)), 629 ]); 630 insta::assert_snapshot!(output, @r" 631 @ Change wqn commit9 ede 632 ○ Change kmk commit8 ef3 633 ○ Change kpq commit7 af9 634 ○ Change znk commit6 23c 635 ○ Change yos commit5 b87 636 ○ Change vru commit4 1ea 637 ○ Change yqo commit3 34b 638 ○ Change roy commit2 cc0 639 ○ Change mzv commit1 1b7 640 ○ Change qpv initial e0e original 641 ◆ Change zzz 000 642 [EOF] 643 "); 644 let output = work_dir.run_jj([ 645 "--color=always", 646 "log", 647 "-r", 648 "@-----------..@", 649 "-T", 650 &prefix_format(None), 651 ]); 652 insta::assert_snapshot!(output, @r" 653 @ Change wq commit9 ed 654 ○ Change km commit8 ef3 655 ○ Change kp commit7 af 656 ○ Change zn commit6 23 657 ○ Change yo commit5 b87 658 ○ Change vr commit4 1e 659 ○ Change yq commit3 34 660 ○ Change ro commit2 cc 661 ○ Change mz commit1 1b 662 ○ Change qpv initial e0 original 663 ◆ Change zzz 00 664 [EOF] 665 "); 666} 667 668#[test] 669fn test_log_prefix_highlight_counts_hidden_commits() { 670 let test_env = TestEnvironment::default(); 671 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 672 let work_dir = test_env.work_dir("repo"); 673 test_env.add_config( 674 r#" 675 [revsets] 676 short-prefixes = "" # Disable short prefixes 677 [template-aliases] 678 'format_id(id)' = 'id.shortest(12).prefix() ++ "[" ++ id.shortest(12).rest() ++ "]"' 679 "#, 680 ); 681 682 let prefix_format = r#" 683 separate(" ", 684 "Change", 685 format_id(change_id), 686 description.first_line(), 687 format_id(commit_id), 688 bookmarks, 689 ) 690 "#; 691 692 work_dir.write_file("file", "original file\n"); 693 work_dir.run_jj(["describe", "-m", "initial"]).success(); 694 work_dir 695 .run_jj(["bookmark", "c", "-r@", "original"]) 696 .success(); 697 insta::assert_snapshot!(work_dir.run_jj(["log", "-r", "all()", "-T", prefix_format]), @r" 698 @ Change q[pvuntsmwlqt] initial e0[e22b9fae75] original 699 ◆ Change z[zzzzzzzzzzz] 0[00000000000] 700 [EOF] 701 "); 702 703 // Create 2^7 hidden commits 704 work_dir.run_jj(["new", "root()", "-m", "extra"]).success(); 705 for _ in 0..7 { 706 work_dir 707 .run_jj(["duplicate", "description(extra)"]) 708 .success(); 709 } 710 work_dir.run_jj(["abandon", "description(extra)"]).success(); 711 712 // The unique prefixes became longer. 713 insta::assert_snapshot!(work_dir.run_jj(["log", "-T", prefix_format]), @r" 714 @ Change wq[nwkozpkust] 44[4c3c5066d3] 715 │ ○ Change qpv[untsmwlqt] initial e0e[22b9fae75] original 716 ├─╯ 717 ◆ Change zzz[zzzzzzzzz] 00[0000000000] 718 [EOF] 719 "); 720 insta::assert_snapshot!(work_dir.run_jj(["log", "-r", "4", "-T", prefix_format]), @r" 721 ------- stderr ------- 722 Error: Commit ID prefix `4` is ambiguous 723 [EOF] 724 [exit status: 1] 725 "); 726 insta::assert_snapshot!(work_dir.run_jj(["log", "-r", "44", "-T", prefix_format]), @r" 727 @ Change wq[nwkozpkust] 44[4c3c5066d3] 728 729 ~ 730 [EOF] 731 "); 732} 733 734#[test] 735fn test_log_short_shortest_length_parameter() { 736 let test_env = TestEnvironment::default(); 737 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 738 let work_dir = test_env.work_dir("repo"); 739 let render = |template| work_dir.run_jj(["log", "-T", template]); 740 741 insta::assert_snapshot!( 742 render(r#"commit_id.short(0) ++ "|" ++ commit_id.shortest(0)"#), @r" 743 @ |2 744 ◆ |0 745 [EOF] 746 "); 747 insta::assert_snapshot!( 748 render(r#"commit_id.short(-0) ++ "|" ++ commit_id.shortest(-0)"#), @r" 749 @ |2 750 ◆ |0 751 [EOF] 752 "); 753 insta::assert_snapshot!( 754 render(r#"commit_id.short(-100) ++ "|" ++ commit_id.shortest(-100)"#), @r" 755 @ <Error: out of range integral type conversion attempted>|<Error: out of range integral type conversion attempted> 756 ◆ <Error: out of range integral type conversion attempted>|<Error: out of range integral type conversion attempted> 757 [EOF] 758 "); 759 insta::assert_snapshot!( 760 render(r#"commit_id.short(100) ++ "|" ++ commit_id.shortest(100)"#), @r" 761 @ 230dd059e1b059aefc0da06a2e5a7dbf22362f22|230dd059e1b059aefc0da06a2e5a7dbf22362f22 762 ◆ 0000000000000000000000000000000000000000|0000000000000000000000000000000000000000 763 [EOF] 764 "); 765} 766 767#[test] 768fn test_log_author_format() { 769 let test_env = TestEnvironment::default(); 770 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 771 let work_dir = test_env.work_dir("repo"); 772 773 insta::assert_snapshot!(work_dir.run_jj(["log", "--revisions=@"]), @r" 774 @ qpvuntsm test.user@example.com 2001-02-03 08:05:07 230dd059 775 │ (empty) (no description set) 776 ~ 777 [EOF] 778 "); 779 780 let decl = "template-aliases.'format_short_signature(signature)'"; 781 insta::assert_snapshot!(work_dir.run_jj([ 782 "--config", 783 &format!("{decl}='signature.email().local()'"), 784 "log", 785 "--revisions=@", 786 ]), @r" 787 @ qpvuntsm test.user 2001-02-03 08:05:07 230dd059 788 │ (empty) (no description set) 789 ~ 790 [EOF] 791 "); 792} 793 794#[test] 795fn test_log_divergence() { 796 let test_env = TestEnvironment::default(); 797 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 798 let work_dir = test_env.work_dir("repo"); 799 let template = r#"description.first_line() ++ if(divergent, " !divergence!")"#; 800 801 work_dir.write_file("file", "foo\n"); 802 work_dir 803 .run_jj(["describe", "-m", "description 1"]) 804 .success(); 805 // No divergence 806 let output = work_dir.run_jj(["log", "-T", template]); 807 insta::assert_snapshot!(output, @r" 808 @ description 1 809 810 [EOF] 811 "); 812 813 // Create divergence 814 work_dir 815 .run_jj(["describe", "-m", "description 2", "--at-operation", "@-"]) 816 .success(); 817 let output = work_dir.run_jj(["log", "-T", template]); 818 insta::assert_snapshot!(output, @r" 819 @ description 1 !divergence! 820 │ ○ description 2 !divergence! 821 ├─╯ 822 823 [EOF] 824 ------- stderr ------- 825 Concurrent modification detected, resolving automatically. 826 [EOF] 827 "); 828} 829 830#[test] 831fn test_log_reversed() { 832 let test_env = TestEnvironment::default(); 833 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 834 let work_dir = test_env.work_dir("repo"); 835 836 work_dir.run_jj(["describe", "-m", "first"]).success(); 837 work_dir.run_jj(["new", "-m", "second"]).success(); 838 839 let output = work_dir.run_jj(["log", "-T", "description", "--reversed"]); 840 insta::assert_snapshot!(output, @r" 841 842 ○ first 843 @ second 844 [EOF] 845 "); 846 847 let output = work_dir.run_jj(["log", "-T", "description", "--reversed", "--no-graph"]); 848 insta::assert_snapshot!(output, @r" 849 first 850 second 851 [EOF] 852 "); 853} 854 855#[test] 856fn test_log_filtered_by_path() { 857 let test_env = TestEnvironment::default(); 858 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 859 let work_dir = test_env.work_dir("repo"); 860 861 work_dir.write_file("file1", "foo\n"); 862 work_dir.run_jj(["describe", "-m", "first"]).success(); 863 work_dir.run_jj(["new", "-m", "second"]).success(); 864 work_dir.write_file("file1", "foo\nbar\n"); 865 work_dir.write_file("file2", "baz\n"); 866 867 let output = work_dir.run_jj(["log", "-T", "description", "file1"]); 868 insta::assert_snapshot!(output, @r" 869 @ second 870 ○ first 871 872 ~ 873 [EOF] 874 "); 875 876 let output = work_dir.run_jj(["log", "-T", "description", "file2"]); 877 insta::assert_snapshot!(output, @r" 878 @ second 879 880 ~ 881 [EOF] 882 "); 883 884 let output = work_dir.run_jj(["log", "-T", "description", "-s", "file1"]); 885 insta::assert_snapshot!(output, @r" 886 @ second 887 │ M file1 888 ○ first 889 │ A file1 890 ~ 891 [EOF] 892 "); 893 894 let output = work_dir.run_jj(["log", "-T", "description", "-s", "file2", "--no-graph"]); 895 insta::assert_snapshot!(output, @r" 896 second 897 A file2 898 [EOF] 899 "); 900 901 // empty revisions are filtered out by "all()" fileset. 902 let output = work_dir.run_jj(["log", "-Tdescription", "-s", "all()"]); 903 insta::assert_snapshot!(output, @r" 904 @ second 905 │ M file1 906 │ A file2 907 ○ first 908 │ A file1 909 ~ 910 [EOF] 911 "); 912 913 // "root:<path>" is resolved relative to the workspace root. 914 let output = test_env.run_jj_in( 915 ".", 916 [ 917 "log", 918 "-R", 919 work_dir.root().to_str().unwrap(), 920 "-Tdescription", 921 "-s", 922 "root:file1", 923 ], 924 ); 925 insta::assert_snapshot!(output.normalize_backslash(), @r" 926 @ second 927 │ M repo/file1 928 ○ first 929 │ A repo/file1 930 ~ 931 [EOF] 932 "); 933 934 // files() revset doesn't filter the diff. 935 let output = work_dir.run_jj([ 936 "log", 937 "-T", 938 "description", 939 "-s", 940 "-rfiles(file2)", 941 "--no-graph", 942 ]); 943 insta::assert_snapshot!(output, @r" 944 second 945 M file1 946 A file2 947 [EOF] 948 "); 949} 950 951#[test] 952fn test_log_limit() { 953 let test_env = TestEnvironment::default(); 954 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 955 let work_dir = test_env.work_dir("repo"); 956 957 work_dir.run_jj(["describe", "-m", "a"]).success(); 958 work_dir.write_file("a", ""); 959 work_dir.run_jj(["new", "-m", "b"]).success(); 960 work_dir.write_file("b", ""); 961 work_dir 962 .run_jj(["new", "-m", "c", "description(a)"]) 963 .success(); 964 work_dir.write_file("c", ""); 965 work_dir 966 .run_jj(["new", "-m", "d", "description(c)", "description(b)"]) 967 .success(); 968 969 let output = work_dir.run_jj(["log", "-T", "description", "--limit=3"]); 970 insta::assert_snapshot!(output, @r" 971 @ d 972 ├─╮ 973 │ ○ b 974 ○ │ c 975 ├─╯ 976 [EOF] 977 "); 978 979 // Applied on sorted DAG 980 let output = work_dir.run_jj(["log", "-T", "description", "--limit=2"]); 981 insta::assert_snapshot!(output, @r" 982 @ d 983 ├─╮ 984 │ ○ b 985 [EOF] 986 "); 987 988 let output = work_dir.run_jj(["log", "-T", "description", "--limit=2", "--no-graph"]); 989 insta::assert_snapshot!(output, @r" 990 d 991 c 992 [EOF] 993 "); 994 995 // Applied on reversed DAG: Because the node "a" is omitted, "b" and "c" are 996 // rendered as roots. 997 let output = work_dir.run_jj(["log", "-T", "description", "--limit=3", "--reversed"]); 998 insta::assert_snapshot!(output, @r" 999 ○ c 1000 │ ○ b 1001 ├─╯ 1002 @ d 1003 [EOF] 1004 "); 1005 let output = work_dir.run_jj([ 1006 "log", 1007 "-T", 1008 "description", 1009 "--limit=3", 1010 "--reversed", 1011 "--no-graph", 1012 ]); 1013 insta::assert_snapshot!(output, @r" 1014 b 1015 c 1016 d 1017 [EOF] 1018 "); 1019 1020 // Applied on filtered commits 1021 let output = work_dir.run_jj(["log", "-T", "description", "--limit=1", "b", "c"]); 1022 insta::assert_snapshot!(output, @r" 1023 ○ c 10241025 ~ 1026 [EOF] 1027 "); 1028} 1029 1030#[test] 1031fn test_log_warn_path_might_be_revset() { 1032 let test_env = TestEnvironment::default(); 1033 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1034 let work_dir = test_env.work_dir("repo"); 1035 1036 work_dir.write_file("file1", "foo\n"); 1037 1038 // Don't warn if the file actually exists. 1039 let output = work_dir.run_jj(["log", "file1", "-T", "description"]); 1040 insta::assert_snapshot!(output, @r" 1041 @ 10421043 ~ 1044 [EOF] 1045 "); 1046 1047 // Warn for `jj log .` specifically, for former Mercurial users. 1048 let output = work_dir.run_jj(["log", ".", "-T", "description"]); 1049 insta::assert_snapshot!(output, @r#" 1050 @ 10511052 ~ 1053 [EOF] 1054 ------- stderr ------- 1055 Warning: The argument "." is being interpreted as a fileset expression, but this is often not useful because all non-empty commits touch '.'. If you meant to show the working copy commit, pass -r '@' instead. 1056 [EOF] 1057 "#); 1058 1059 // ...but checking `jj log .` makes sense in a subdirectory. 1060 let sub_dir = work_dir.create_dir_all("dir"); 1061 let output = sub_dir.run_jj(["log", "."]); 1062 insta::assert_snapshot!(output, @""); 1063 1064 // Warn for `jj log @` instead of `jj log -r @`. 1065 let output = work_dir.run_jj(["log", "@", "-T", "description"]); 1066 insta::assert_snapshot!(output, @r#" 1067 ------- stderr ------- 1068 Warning: The argument "@" is being interpreted as a fileset expression. To specify a revset, pass -r "@" instead. 1069 [EOF] 1070 "#); 1071 1072 // Warn when there's no path with the provided name. 1073 let output = work_dir.run_jj(["log", "file2", "-T", "description"]); 1074 insta::assert_snapshot!(output, @r#" 1075 ------- stderr ------- 1076 Warning: The argument "file2" is being interpreted as a fileset expression. To specify a revset, pass -r "file2" instead. 1077 [EOF] 1078 "#); 1079 1080 // If an explicit revision is provided, then suppress the warning. 1081 let output = work_dir.run_jj(["log", "@", "-r", "@", "-T", "description"]); 1082 insta::assert_snapshot!(output, @""); 1083} 1084 1085#[test] 1086fn test_default_revset() { 1087 let test_env = TestEnvironment::default(); 1088 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1089 let work_dir = test_env.work_dir("repo"); 1090 1091 work_dir.write_file("file1", "foo\n"); 1092 work_dir.run_jj(["describe", "-m", "add a file"]).success(); 1093 1094 // Set configuration to only show the root commit. 1095 test_env.add_config(r#"revsets.log = "root()""#); 1096 1097 // Log should only contain one line (for the root commit), and not show the 1098 // commit created above. 1099 insta::assert_snapshot!(work_dir.run_jj(["log", "-T", "commit_id"]), @r" 1100 ◆ 0000000000000000000000000000000000000000 1101 [EOF] 1102 "); 1103 1104 // The default revset is not used if a path is specified 1105 insta::assert_snapshot!(work_dir.run_jj(["log", "file1", "-T", "description"]), @r" 1106 @ add a file 11071108 ~ 1109 [EOF] 1110 "); 1111} 1112 1113#[test] 1114fn test_default_revset_per_repo() { 1115 let test_env = TestEnvironment::default(); 1116 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1117 let work_dir = test_env.work_dir("repo"); 1118 1119 work_dir.write_file("file1", "foo\n"); 1120 work_dir.run_jj(["describe", "-m", "add a file"]).success(); 1121 1122 // Set configuration to only show the root commit. 1123 work_dir.write_file(".jj/repo/config.toml", r#"revsets.log = "root()""#); 1124 1125 // Log should only contain one line (for the root commit), and not show the 1126 // commit created above. 1127 insta::assert_snapshot!(work_dir.run_jj(["log", "-T", "commit_id"]), @r" 1128 ◆ 0000000000000000000000000000000000000000 1129 [EOF] 1130 "); 1131} 1132 1133#[test] 1134fn test_multiple_revsets() { 1135 let test_env = TestEnvironment::default(); 1136 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1137 let work_dir = test_env.work_dir("repo"); 1138 for name in ["foo", "bar", "baz"] { 1139 work_dir.run_jj(["new", "-m", name]).success(); 1140 work_dir 1141 .run_jj(["bookmark", "create", "-r@", name]) 1142 .success(); 1143 } 1144 1145 // Default revset should be overridden if one or more -r options are specified. 1146 test_env.add_config(r#"revsets.log = "root()""#); 1147 1148 insta::assert_snapshot!( 1149 work_dir.run_jj(["log", "-T", "bookmarks", "-rfoo"]), @r" 1150 ○ foo 11511152 ~ 1153 [EOF] 1154 "); 1155 insta::assert_snapshot!( 1156 work_dir.run_jj(["log", "-T", "bookmarks", "-rfoo", "-rbar", "-rbaz"]), @r" 1157 @ baz 1158 ○ bar 1159 ○ foo 11601161 ~ 1162 [EOF] 1163 "); 1164 insta::assert_snapshot!( 1165 work_dir.run_jj(["log", "-T", "bookmarks", "-rfoo", "-rfoo"]), @r" 1166 ○ foo 11671168 ~ 1169 [EOF] 1170 "); 1171} 1172 1173#[test] 1174fn test_graph_template_color() { 1175 // Test that color codes from a multi-line template don't span the graph lines. 1176 let test_env = TestEnvironment::default(); 1177 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1178 let work_dir = test_env.work_dir("repo"); 1179 1180 work_dir 1181 .run_jj(["describe", "-m", "first line\nsecond line\nthird line"]) 1182 .success(); 1183 work_dir.run_jj(["new", "-m", "single line"]).success(); 1184 1185 test_env.add_config( 1186 r#"[colors] 1187 description = "red" 1188 "working_copy description" = "green" 1189 "#, 1190 ); 1191 1192 // First test without color for comparison 1193 let template = r#"label(if(current_working_copy, "working_copy"), description)"#; 1194 let output = work_dir.run_jj(["log", "-T", template]); 1195 insta::assert_snapshot!(output, @r" 1196 @ single line 1197 ○ first line 1198 │ second line 1199 │ third line 12001201 [EOF] 1202 "); 1203 let output = work_dir.run_jj(["--color=always", "log", "-T", template]); 1204 insta::assert_snapshot!(output, @r" 1205 @ single line 1206 ○ first line 1207 │ second line 1208 │ third line 1209 ◆ 1210 [EOF] 1211 "); 1212 let output = work_dir.run_jj(["--color=debug", "log", "-T", template]); 1213 insta::assert_snapshot!(output, @r" 1214 <<node working_copy::@>> <<log working_copy description::single line>> 1215 <<node::○>> <<log description::first line>> 1216 │ <<log description::second line>> 1217 │ <<log description::third line>> 1218 <<node immutable::◆>> 1219 [EOF] 1220 "); 1221} 1222 1223#[test] 1224fn test_graph_styles() { 1225 // Test that different graph styles are available. 1226 let test_env = TestEnvironment::default(); 1227 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1228 let work_dir = test_env.work_dir("repo"); 1229 1230 work_dir.run_jj(["commit", "-m", "initial"]).success(); 1231 work_dir 1232 .run_jj(["commit", "-m", "main bookmark 1"]) 1233 .success(); 1234 work_dir 1235 .run_jj(["describe", "-m", "main bookmark 2"]) 1236 .success(); 1237 work_dir 1238 .run_jj(["new", "-m", "side bookmark\nwith\nlong\ndescription"]) 1239 .success(); 1240 work_dir 1241 .run_jj([ 1242 "new", 1243 "-m", 1244 "merge", 1245 r#"description("main bookmark 1")"#, 1246 "@", 1247 ]) 1248 .success(); 1249 1250 // Default (curved) style 1251 let output = work_dir.run_jj(["log", "-T=description"]); 1252 insta::assert_snapshot!(output, @r" 1253 @ merge 1254 ├─╮ 1255 │ ○ side bookmark 1256 │ │ with 1257 │ │ long 1258 │ │ description 1259 │ ○ main bookmark 2 1260 ├─╯ 1261 ○ main bookmark 1 1262 ○ initial 12631264 [EOF] 1265 "); 1266 1267 // ASCII style 1268 test_env.add_config(r#"ui.graph.style = "ascii""#); 1269 let output = work_dir.run_jj(["log", "-T=description"]); 1270 insta::assert_snapshot!(output, @r" 1271 @ merge 1272 |\ 1273 | o side bookmark 1274 | | with 1275 | | long 1276 | | description 1277 | o main bookmark 2 1278 |/ 1279 o main bookmark 1 1280 o initial 1281 + 1282 [EOF] 1283 "); 1284 1285 // Large ASCII style 1286 test_env.add_config(r#"ui.graph.style = "ascii-large""#); 1287 let output = work_dir.run_jj(["log", "-T=description"]); 1288 insta::assert_snapshot!(output, @r" 1289 @ merge 1290 |\ 1291 | \ 1292 | o side bookmark 1293 | | with 1294 | | long 1295 | | description 1296 | o main bookmark 2 1297 | / 1298 |/ 1299 o main bookmark 1 1300 o initial 1301 + 1302 [EOF] 1303 "); 1304 1305 // Curved style 1306 test_env.add_config(r#"ui.graph.style = "curved""#); 1307 let output = work_dir.run_jj(["log", "-T=description"]); 1308 insta::assert_snapshot!(output, @r" 1309 @ merge 1310 ├─╮ 1311 │ ○ side bookmark 1312 │ │ with 1313 │ │ long 1314 │ │ description 1315 │ ○ main bookmark 2 1316 ├─╯ 1317 ○ main bookmark 1 1318 ○ initial 13191320 [EOF] 1321 "); 1322 1323 // Square style 1324 test_env.add_config(r#"ui.graph.style = "square""#); 1325 let output = work_dir.run_jj(["log", "-T=description"]); 1326 insta::assert_snapshot!(output, @r" 1327 @ merge 1328 ├─┐ 1329 │ ○ side bookmark 1330 │ │ with 1331 │ │ long 1332 │ │ description 1333 │ ○ main bookmark 2 1334 ├─┘ 1335 ○ main bookmark 1 1336 ○ initial 13371338 [EOF] 1339 "); 1340 1341 // Invalid style name 1342 let output = work_dir.run_jj(["log", "--config=ui.graph.style=unknown"]); 1343 insta::assert_snapshot!(output, @r" 1344 ------- stderr ------- 1345 Config error: Invalid type or value for ui.graph.style 1346 Caused by: unknown variant `unknown`, expected one of `ascii`, `ascii-large`, `curved`, `square` 1347 1348 For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. 1349 [EOF] 1350 [exit status: 1] 1351 "); 1352} 1353 1354#[test] 1355fn test_log_word_wrap() { 1356 let test_env = TestEnvironment::default(); 1357 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1358 let work_dir = test_env.work_dir("repo"); 1359 let render = |args: &[&str], columns: u32, word_wrap: bool| { 1360 let word_wrap = to_toml_value(word_wrap); 1361 work_dir.run_jj_with(|cmd| { 1362 cmd.args(args) 1363 .arg(format!("--config=ui.log-word-wrap={word_wrap}")) 1364 .env("COLUMNS", columns.to_string()) 1365 }) 1366 }; 1367 1368 work_dir 1369 .run_jj(["commit", "-m", "main bookmark 1"]) 1370 .success(); 1371 work_dir 1372 .run_jj(["describe", "-m", "main bookmark 2"]) 1373 .success(); 1374 work_dir.run_jj(["new", "-m", "side"]).success(); 1375 work_dir 1376 .run_jj(["new", "-m", "merge", "@--", "@"]) 1377 .success(); 1378 1379 // ui.log-word-wrap option applies to both graph/no-graph outputs 1380 insta::assert_snapshot!(render(&["log", "-r@"], 40, false), @r" 1381 @ mzvwutvl test.user@example.com 2001-02-03 08:05:11 f3efbd00 1382 │ (empty) merge 1383 ~ 1384 [EOF] 1385 "); 1386 insta::assert_snapshot!(render(&["log", "-r@"], 40, true), @r" 1387 @ mzvwutvl test.user@example.com 1388 │ 2001-02-03 08:05:11 f3efbd00 1389 ~ (empty) merge 1390 [EOF] 1391 "); 1392 insta::assert_snapshot!(render(&["log", "--no-graph", "-r@"], 40, false), @r" 1393 mzvwutvl test.user@example.com 2001-02-03 08:05:11 f3efbd00 1394 (empty) merge 1395 [EOF] 1396 "); 1397 insta::assert_snapshot!(render(&["log", "--no-graph", "-r@"], 40, true), @r" 1398 mzvwutvl test.user@example.com 1399 2001-02-03 08:05:11 f3efbd00 1400 (empty) merge 1401 [EOF] 1402 "); 1403 1404 // Color labels should be preserved 1405 insta::assert_snapshot!(render(&["log", "-r@", "--color=always"], 40, true), @r" 1406 @ mzvwutvl test.user@example.com 1407 │ 2001-02-03 08:05:11 f3efbd00 1408 ~ (empty) merge 1409 [EOF] 1410 "); 1411 1412 // Graph width should be subtracted from the term width 1413 let template = r#""0 1 2 3 4 5 6 7 8 9""#; 1414 insta::assert_snapshot!(render(&["log", "-T", template], 10, true), @r" 1415 @ 0 1 2 1416 ├─╮ 3 4 5 1417 │ │ 6 7 8 1418 │ │ 9 1419 │ ○ 0 1 2 1420 │ │ 3 4 5 1421 │ │ 6 7 8 1422 │ │ 9 1423 │ ○ 0 1 2 1424 ├─╯ 3 4 5 1425 │ 6 7 8 1426 │ 9 1427 ○ 0 1 2 3 1428 │ 4 5 6 7 1429 │ 8 9 1430 ◆ 0 1 2 3 1431 4 5 6 7 1432 8 9 1433 [EOF] 1434 "); 1435 1436 // Shouldn't panic with $COLUMNS < graph_width 1437 insta::assert_snapshot!(render(&["log", "-r@"], 0, true), @r" 1438 @ mzvwutvl 1439 │ test.user@example.com 1440 ~ 2001-02-03 1441 08:05:11 1442 f3efbd00 1443 (empty) 1444 merge 1445 [EOF] 1446 "); 1447 insta::assert_snapshot!(render(&["log", "-r@"], 1, true), @r" 1448 @ mzvwutvl 1449 │ test.user@example.com 1450 ~ 2001-02-03 1451 08:05:11 1452 f3efbd00 1453 (empty) 1454 merge 1455 [EOF] 1456 "); 1457} 1458 1459#[test] 1460fn test_log_diff_stat_width() { 1461 let test_env = TestEnvironment::default(); 1462 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1463 let work_dir = test_env.work_dir("repo"); 1464 let render = |args: &[&str], columns: u32| { 1465 work_dir.run_jj_with(|cmd| cmd.args(args).env("COLUMNS", columns.to_string())) 1466 }; 1467 1468 work_dir.write_file("file1", "foo\n".repeat(100)); 1469 work_dir.run_jj(["new", "root()"]).success(); 1470 work_dir.write_file("file2", "foo\n".repeat(100)); 1471 1472 insta::assert_snapshot!(render(&["log", "--stat", "--no-graph"], 30), @r" 1473 rlvkpnrz test.user@example.com 2001-02-03 08:05:09 287520bf 1474 (no description set) 1475 file2 | 100 +++++++++++++++ 1476 1 file changed, 100 insertions(+), 0 deletions(-) 1477 qpvuntsm test.user@example.com 2001-02-03 08:05:08 e292def1 1478 (no description set) 1479 file1 | 100 +++++++++++++++ 1480 1 file changed, 100 insertions(+), 0 deletions(-) 1481 zzzzzzzz root() 00000000 1482 0 files changed, 0 insertions(+), 0 deletions(-) 1483 [EOF] 1484 "); 1485 1486 // Graph width should be subtracted 1487 insta::assert_snapshot!(render(&["log", "--stat"], 30), @r" 1488 @ rlvkpnrz test.user@example.com 2001-02-03 08:05:09 287520bf 1489 │ (no description set) 1490 │ file2 | 100 ++++++++++++ 1491 │ 1 file changed, 100 insertions(+), 0 deletions(-) 1492 │ ○ qpvuntsm test.user@example.com 2001-02-03 08:05:08 e292def1 1493 ├─╯ (no description set) 1494 │ file1 | 100 ++++++++++ 1495 │ 1 file changed, 100 insertions(+), 0 deletions(-) 1496 ◆ zzzzzzzz root() 00000000 1497 0 files changed, 0 insertions(+), 0 deletions(-) 1498 [EOF] 1499 "); 1500} 1501 1502#[test] 1503fn test_elided() { 1504 // Test that elided commits are shown as synthetic nodes. 1505 let test_env = TestEnvironment::default(); 1506 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1507 let work_dir = test_env.work_dir("repo"); 1508 1509 work_dir.run_jj(["describe", "-m", "initial"]).success(); 1510 work_dir.run_jj(["new", "-m", "main bookmark 1"]).success(); 1511 work_dir.run_jj(["new", "-m", "main bookmark 2"]).success(); 1512 work_dir 1513 .run_jj(["new", "@--", "-m", "side bookmark 1"]) 1514 .success(); 1515 work_dir.run_jj(["new", "-m", "side bookmark 2"]).success(); 1516 work_dir 1517 .run_jj([ 1518 "new", 1519 "-m", 1520 "merge", 1521 r#"description("main bookmark 2")"#, 1522 "@", 1523 ]) 1524 .success(); 1525 1526 let get_log = |revs: &str| work_dir.run_jj(["log", "-T", r#"description ++ "\n""#, "-r", revs]); 1527 1528 // Test the setup 1529 insta::assert_snapshot!(get_log("::"), @r" 1530 @ merge 1531 ├─╮ 1532 │ ○ side bookmark 2 1533 │ │ 1534 │ ○ side bookmark 1 1535 │ │ 1536 ○ │ main bookmark 2 1537 │ │ 1538 ○ │ main bookmark 1 1539 ├─╯ 1540 ○ initial 154115421543 [EOF] 1544 "); 1545 1546 // Elide some commits from each side of the merge. It's unclear that a revision 1547 // was skipped on the left side. 1548 test_env.add_config("ui.log-synthetic-elided-nodes = false"); 1549 insta::assert_snapshot!(get_log("@ | @- | description(initial)"), @r" 1550 @ merge 1551 ├─╮ 1552 │ ○ side bookmark 2 1553 │ ╷ 1554 ○ ╷ main bookmark 2 1555 ├─╯ 1556 ○ initial 15571558 ~ 1559 [EOF] 1560 "); 1561 1562 // Elide shared commits. It's unclear that a revision was skipped on the right 1563 // side (#1252). 1564 insta::assert_snapshot!(get_log("@-- | root()"), @r" 1565 ○ side bookmark 1 15661567 ╷ ○ main bookmark 1 1568 ╭─╯ 15691570 [EOF] 1571 "); 1572 1573 // Now test the same thing with synthetic nodes for elided commits 1574 1575 // Elide some commits from each side of the merge 1576 test_env.add_config("ui.log-synthetic-elided-nodes = true"); 1577 insta::assert_snapshot!(get_log("@ | @- | description(initial)"), @r" 1578 @ merge 1579 ├─╮ 1580 │ ○ side bookmark 2 1581 │ │ 1582 │ ~ (elided revisions) 1583 ○ │ main bookmark 2 1584 │ │ 1585 ~ │ (elided revisions) 1586 ├─╯ 1587 ○ initial 15881589 ~ 1590 [EOF] 1591 "); 1592 1593 // Elide shared commits. To keep the implementation simple, it still gets 1594 // rendered as two synthetic nodes. 1595 insta::assert_snapshot!(get_log("@-- | root()"), @r" 1596 ○ side bookmark 1 15971598 ~ (elided revisions) 1599 │ ○ main bookmark 1 1600 │ │ 1601 │ ~ (elided revisions) 1602 ├─╯ 16031604 [EOF] 1605 "); 1606} 1607 1608#[test] 1609fn test_log_with_custom_symbols() { 1610 // Test that elided commits are shown as synthetic nodes. 1611 let test_env = TestEnvironment::default(); 1612 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1613 let work_dir = test_env.work_dir("repo"); 1614 1615 work_dir.run_jj(["describe", "-m", "initial"]).success(); 1616 work_dir.run_jj(["new", "-m", "main bookmark 1"]).success(); 1617 work_dir.run_jj(["new", "-m", "main bookmark 2"]).success(); 1618 work_dir 1619 .run_jj(["new", "@--", "-m", "side bookmark 1"]) 1620 .success(); 1621 work_dir.run_jj(["new", "-m", "side bookmark 2"]).success(); 1622 work_dir 1623 .run_jj([ 1624 "new", 1625 "-m", 1626 "merge", 1627 r#"description("main bookmark 2")"#, 1628 "@", 1629 ]) 1630 .success(); 1631 1632 let get_log = |revs: &str| work_dir.run_jj(["log", "-T", r#"description ++ "\n""#, "-r", revs]); 1633 1634 // Simple test with showing default and elided nodes. 1635 test_env.add_config( 1636 r###" 1637 ui.log-synthetic-elided-nodes = true 1638 templates.log_node = 'if(self, if(current_working_copy, "$", if(root, "┴", "┝")), "🮀")' 1639 "###, 1640 ); 1641 insta::assert_snapshot!(get_log("@ | @- | description(initial) | root()"), @r" 1642 $ merge 1643 ├─╮ 1644 │ ┝ side bookmark 2 1645 │ │ 1646 │ 🮀 (elided revisions) 1647 ┝ │ main bookmark 2 1648 │ │ 1649 🮀 │ (elided revisions) 1650 ├─╯ 1651 ┝ initial 165216531654 [EOF] 1655 "); 1656 1657 // Simple test with showing default and elided nodes, ascii style. 1658 test_env.add_config( 1659 r###" 1660 ui.log-synthetic-elided-nodes = true 1661 ui.graph.style = 'ascii' 1662 templates.log_node = 'if(self, if(current_working_copy, "$", if(root, "^", "*")), ":")' 1663 "###, 1664 ); 1665 insta::assert_snapshot!(get_log("@ | @- | description(initial) | root()"), @r" 1666 $ merge 1667 |\ 1668 | * side bookmark 2 1669 | | 1670 | : (elided revisions) 1671 * | main bookmark 2 1672 | | 1673 : | (elided revisions) 1674 |/ 1675 * initial 1676 | 1677 ^ 1678 [EOF] 1679 "); 1680} 1681 1682#[test] 1683fn test_log_full_description_template() { 1684 let test_env = TestEnvironment::default(); 1685 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1686 let work_dir = test_env.work_dir("repo"); 1687 1688 work_dir 1689 .run_jj([ 1690 "describe", 1691 "-m", 1692 "this is commit with a multiline description\n\n<full description>", 1693 ]) 1694 .success(); 1695 1696 let output = work_dir.run_jj(["log", "-T", "builtin_log_compact_full_description"]); 1697 insta::assert_snapshot!(output, @r" 1698 @ qpvuntsm test.user@example.com 2001-02-03 08:05:08 1c504ec6 1699 │ (empty) this is commit with a multiline description 17001701 │ <full description> 17021703 ◆ zzzzzzzz root() 00000000 1704 [EOF] 1705 "); 1706}