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