just playing with tangled
at gvimdiff 88 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 indoc::indoc; 16use itertools::Itertools as _; 17 18use crate::common::create_commit; 19use crate::common::fake_diff_editor_path; 20use crate::common::to_toml_value; 21use crate::common::CommandOutput; 22use crate::common::TestEnvironment; 23use crate::common::TestWorkDir; 24 25#[test] 26fn test_diff_basic() { 27 let test_env = TestEnvironment::default(); 28 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 29 let work_dir = test_env.work_dir("repo"); 30 31 work_dir.write_file("file1", "foo\n"); 32 work_dir.write_file("file2", "1\n2\n3\n4\n"); 33 work_dir.run_jj(["new"]).success(); 34 work_dir.remove_file("file1"); 35 work_dir.write_file("file2", "1\n5\n3\n"); 36 work_dir.write_file("file3", "foo\n"); 37 work_dir.write_file("file4", "1\n2\n3\n4\n"); 38 39 let output = work_dir.run_jj(["diff"]); 40 insta::assert_snapshot!(output, @r" 41 Modified regular file file2: 42 1 1: 1 43 2 2: 25 44 3 3: 3 45 4 : 4 46 Modified regular file file3 (file1 => file3): 47 Modified regular file file4 (file2 => file4): 48 [EOF] 49 "); 50 51 let output = work_dir.run_jj(["diff", "--context=0"]); 52 insta::assert_snapshot!(output, @r" 53 Modified regular file file2: 54 1 1: 1 55 2 2: 25 56 3 3: 3 57 4 : 4 58 Modified regular file file3 (file1 => file3): 59 Modified regular file file4 (file2 => file4): 60 [EOF] 61 "); 62 63 let output = work_dir.run_jj(["diff", "--color=debug"]); 64 insta::assert_snapshot!(output, @r" 65 <<diff header::Modified regular file file2:>> 66 <<diff removed line_number:: 1>><<diff:: >><<diff added line_number:: 1>><<diff::: 1>> 67 <<diff removed line_number:: 2>><<diff:: >><<diff added line_number:: 2>><<diff::: >><<diff removed token::2>><<diff added token::5>><<diff::>> 68 <<diff removed line_number:: 3>><<diff:: >><<diff added line_number:: 3>><<diff::: 3>> 69 <<diff removed line_number:: 4>><<diff:: : >><<diff removed token::4>> 70 <<diff header::Modified regular file file3 (file1 => file3):>> 71 <<diff header::Modified regular file file4 (file2 => file4):>> 72 [EOF] 73 "); 74 75 let output = work_dir.run_jj(["diff", "-s"]); 76 insta::assert_snapshot!(output, @r" 77 M file2 78 R {file1 => file3} 79 C {file2 => file4} 80 [EOF] 81 "); 82 83 let output = work_dir.run_jj(["diff", "--types"]); 84 insta::assert_snapshot!(output, @r" 85 FF file2 86 FF {file1 => file3} 87 FF {file2 => file4} 88 [EOF] 89 "); 90 91 let output = work_dir.run_jj(["diff", "--types", "glob:file[12]"]); 92 insta::assert_snapshot!(output, @r" 93 F- file1 94 FF file2 95 [EOF] 96 "); 97 98 let output = work_dir.run_jj(["diff", "--git", "file1"]); 99 insta::assert_snapshot!(output, @r" 100 diff --git a/file1 b/file1 101 deleted file mode 100644 102 index 257cc5642c..0000000000 103 --- a/file1 104 +++ /dev/null 105 @@ -1,1 +0,0 @@ 106 -foo 107 [EOF] 108 "); 109 110 let output = work_dir.run_jj(["diff", "--git"]); 111 insta::assert_snapshot!(output, @r" 112 diff --git a/file2 b/file2 113 index 94ebaf9001..1ffc51b472 100644 114 --- a/file2 115 +++ b/file2 116 @@ -1,4 +1,3 @@ 117 1 118 -2 119 +5 120 3 121 -4 122 diff --git a/file1 b/file3 123 rename from file1 124 rename to file3 125 diff --git a/file2 b/file4 126 copy from file2 127 copy to file4 128 [EOF] 129 "); 130 131 let output = work_dir.run_jj(["diff", "--git", "--context=0"]); 132 insta::assert_snapshot!(output, @r" 133 diff --git a/file2 b/file2 134 index 94ebaf9001..1ffc51b472 100644 135 --- a/file2 136 +++ b/file2 137 @@ -2,1 +2,1 @@ 138 -2 139 +5 140 @@ -4,1 +3,0 @@ 141 -4 142 diff --git a/file1 b/file3 143 rename from file1 144 rename to file3 145 diff --git a/file2 b/file4 146 copy from file2 147 copy to file4 148 [EOF] 149 "); 150 151 let output = work_dir.run_jj(["diff", "--git", "--color=debug"]); 152 insta::assert_snapshot!(output, @r" 153 <<diff file_header::diff --git a/file2 b/file2>> 154 <<diff file_header::index 94ebaf9001..1ffc51b472 100644>> 155 <<diff file_header::--- a/file2>> 156 <<diff file_header::+++ b/file2>> 157 <<diff hunk_header::@@ -1,4 +1,3 @@>> 158 <<diff context:: 1>> 159 <<diff removed::->><<diff removed token::2>><<diff removed::>> 160 <<diff added::+>><<diff added token::5>><<diff added::>> 161 <<diff context:: 3>> 162 <<diff removed::->><<diff removed token::4>> 163 <<diff file_header::diff --git a/file1 b/file3>> 164 <<diff file_header::rename from file1>> 165 <<diff file_header::rename to file3>> 166 <<diff file_header::diff --git a/file2 b/file4>> 167 <<diff file_header::copy from file2>> 168 <<diff file_header::copy to file4>> 169 [EOF] 170 "); 171 172 let output = work_dir.run_jj(["diff", "-s", "--git"]); 173 insta::assert_snapshot!(output, @r" 174 M file2 175 R {file1 => file3} 176 C {file2 => file4} 177 diff --git a/file2 b/file2 178 index 94ebaf9001..1ffc51b472 100644 179 --- a/file2 180 +++ b/file2 181 @@ -1,4 +1,3 @@ 182 1 183 -2 184 +5 185 3 186 -4 187 diff --git a/file1 b/file3 188 rename from file1 189 rename to file3 190 diff --git a/file2 b/file4 191 copy from file2 192 copy to file4 193 [EOF] 194 "); 195 196 let output = work_dir.run_jj(["diff", "--stat"]); 197 insta::assert_snapshot!(output, @r" 198 file2 | 3 +-- 199 {file1 => file3} | 0 200 {file2 => file4} | 0 201 3 files changed, 1 insertion(+), 2 deletions(-) 202 [EOF] 203 "); 204 205 // Filter by glob pattern 206 let output = work_dir.run_jj(["diff", "-s", "glob:file[12]"]); 207 insta::assert_snapshot!(output, @r" 208 D file1 209 M file2 210 [EOF] 211 "); 212 213 // Unmatched paths should generate warnings 214 let output = test_env.run_jj_in( 215 ".", 216 [ 217 "diff", 218 "-Rrepo", 219 "-s", 220 "repo", // matches directory 221 "repo/file1", // deleted in to_tree, but exists in from_tree 222 "repo/x", 223 "repo/y/z", 224 ], 225 ); 226 insta::assert_snapshot!(output.normalize_backslash(), @r" 227 M repo/file2 228 R repo/{file1 => file3} 229 C repo/{file2 => file4} 230 [EOF] 231 ------- stderr ------- 232 Warning: No matching entries for paths: repo/x, repo/y/z 233 [EOF] 234 "); 235 236 // Unmodified paths shouldn't generate warnings 237 let output = work_dir.run_jj(["diff", "-s", "--from=@", "file2"]); 238 insta::assert_snapshot!(output, @""); 239} 240 241#[test] 242fn test_diff_empty() { 243 let test_env = TestEnvironment::default(); 244 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 245 let work_dir = test_env.work_dir("repo"); 246 247 work_dir.write_file("file1", ""); 248 let output = work_dir.run_jj(["diff"]); 249 insta::assert_snapshot!(output, @r" 250 Added regular file file1: 251 (empty) 252 [EOF] 253 "); 254 255 work_dir.run_jj(["new"]).success(); 256 work_dir.remove_file("file1"); 257 let output = work_dir.run_jj(["diff"]); 258 insta::assert_snapshot!(output, @r" 259 Removed regular file file1: 260 (empty) 261 [EOF] 262 "); 263 264 let output = work_dir.run_jj(["diff", "--stat"]); 265 insta::assert_snapshot!(output, @r" 266 file1 | 0 267 1 file changed, 0 insertions(+), 0 deletions(-) 268 [EOF] 269 "); 270} 271 272#[test] 273fn test_diff_file_mode() { 274 let test_env = TestEnvironment::default(); 275 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 276 let work_dir = test_env.work_dir("repo"); 277 278 // Test content+mode/mode-only changes of empty/non-empty files: 279 // - file1: ("", x) -> ("2", n) empty, content+mode 280 // - file2: ("1", x) -> ("1", n) non-empty, mode-only 281 // - file3: ("1", n) -> ("2", x) non-empty, content+mode 282 // - file4: ("", n) -> ("", x) empty, mode-only 283 284 work_dir.write_file("file1", ""); 285 work_dir.write_file("file2", "1\n"); 286 work_dir.write_file("file3", "1\n"); 287 work_dir.write_file("file4", ""); 288 work_dir 289 .run_jj(["file", "chmod", "x", "file1", "file2"]) 290 .success(); 291 292 work_dir.run_jj(["new"]).success(); 293 work_dir.write_file("file1", "2\n"); 294 work_dir.write_file("file3", "2\n"); 295 work_dir 296 .run_jj(["file", "chmod", "n", "file1", "file2"]) 297 .success(); 298 work_dir 299 .run_jj(["file", "chmod", "x", "file3", "file4"]) 300 .success(); 301 302 work_dir.run_jj(["new"]).success(); 303 work_dir.remove_file("file1"); 304 work_dir.remove_file("file2"); 305 work_dir.remove_file("file3"); 306 work_dir.remove_file("file4"); 307 308 let output = work_dir.run_jj(["diff", "-r@--"]); 309 insta::assert_snapshot!(output, @r" 310 Added executable file file1: 311 (empty) 312 Added executable file file2: 313 1: 1 314 Added regular file file3: 315 1: 1 316 Added regular file file4: 317 (empty) 318 [EOF] 319 "); 320 let output = work_dir.run_jj(["diff", "-r@-"]); 321 insta::assert_snapshot!(output, @r" 322 Executable file became non-executable at file1: 323 1: 2 324 Executable file became non-executable at file2: 325 Non-executable file became executable at file3: 326 1 1: 12 327 Non-executable file became executable at file4: 328 [EOF] 329 "); 330 let output = work_dir.run_jj(["diff", "-r@"]); 331 insta::assert_snapshot!(output, @r" 332 Removed regular file file1: 333 1 : 2 334 Removed regular file file2: 335 1 : 1 336 Removed executable file file3: 337 1 : 2 338 Removed executable file file4: 339 (empty) 340 [EOF] 341 "); 342 343 let output = work_dir.run_jj(["diff", "-r@--", "--git"]); 344 insta::assert_snapshot!(output, @r" 345 diff --git a/file1 b/file1 346 new file mode 100755 347 index 0000000000..e69de29bb2 348 diff --git a/file2 b/file2 349 new file mode 100755 350 index 0000000000..d00491fd7e 351 --- /dev/null 352 +++ b/file2 353 @@ -0,0 +1,1 @@ 354 +1 355 diff --git a/file3 b/file3 356 new file mode 100644 357 index 0000000000..d00491fd7e 358 --- /dev/null 359 +++ b/file3 360 @@ -0,0 +1,1 @@ 361 +1 362 diff --git a/file4 b/file4 363 new file mode 100644 364 index 0000000000..e69de29bb2 365 [EOF] 366 "); 367 let output = work_dir.run_jj(["diff", "-r@-", "--git"]); 368 insta::assert_snapshot!(output, @r" 369 diff --git a/file1 b/file1 370 old mode 100755 371 new mode 100644 372 index e69de29bb2..0cfbf08886 373 --- a/file1 374 +++ b/file1 375 @@ -0,0 +1,1 @@ 376 +2 377 diff --git a/file2 b/file2 378 old mode 100755 379 new mode 100644 380 diff --git a/file3 b/file3 381 old mode 100644 382 new mode 100755 383 index d00491fd7e..0cfbf08886 384 --- a/file3 385 +++ b/file3 386 @@ -1,1 +1,1 @@ 387 -1 388 +2 389 diff --git a/file4 b/file4 390 old mode 100644 391 new mode 100755 392 [EOF] 393 "); 394 let output = work_dir.run_jj(["diff", "-r@", "--git"]); 395 insta::assert_snapshot!(output, @r" 396 diff --git a/file1 b/file1 397 deleted file mode 100644 398 index 0cfbf08886..0000000000 399 --- a/file1 400 +++ /dev/null 401 @@ -1,1 +0,0 @@ 402 -2 403 diff --git a/file2 b/file2 404 deleted file mode 100644 405 index d00491fd7e..0000000000 406 --- a/file2 407 +++ /dev/null 408 @@ -1,1 +0,0 @@ 409 -1 410 diff --git a/file3 b/file3 411 deleted file mode 100755 412 index 0cfbf08886..0000000000 413 --- a/file3 414 +++ /dev/null 415 @@ -1,1 +0,0 @@ 416 -2 417 diff --git a/file4 b/file4 418 deleted file mode 100755 419 index e69de29bb2..0000000000 420 [EOF] 421 "); 422} 423 424#[test] 425fn test_diff_types() { 426 let test_env = TestEnvironment::default(); 427 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 428 let work_dir = test_env.work_dir("repo"); 429 430 let file_path = "foo"; 431 432 // Missing 433 work_dir.run_jj(["new", "root()", "-m=missing"]).success(); 434 435 // Normal file 436 work_dir.run_jj(["new", "root()", "-m=file"]).success(); 437 work_dir.write_file(file_path, "foo"); 438 439 // Conflict (add/add) 440 work_dir.run_jj(["new", "root()", "-m=conflict"]).success(); 441 work_dir.write_file(file_path, "foo"); 442 work_dir.run_jj(["new", "root()"]).success(); 443 work_dir.write_file(file_path, "bar"); 444 work_dir 445 .run_jj(["squash", r#"--into=description("conflict")"#]) 446 .success(); 447 448 #[cfg(unix)] 449 { 450 use std::os::unix::fs::PermissionsExt as _; 451 use std::path::PathBuf; 452 453 // Executable 454 work_dir 455 .run_jj(["new", "root()", "-m=executable"]) 456 .success(); 457 work_dir.write_file(file_path, "foo"); 458 std::fs::set_permissions( 459 work_dir.root().join(file_path), 460 std::fs::Permissions::from_mode(0o755), 461 ) 462 .unwrap(); 463 464 // Symlink 465 work_dir.run_jj(["new", "root()", "-m=symlink"]).success(); 466 std::os::unix::fs::symlink(PathBuf::from("."), work_dir.root().join(file_path)).unwrap(); 467 } 468 469 let diff = |from: &str, to: &str| { 470 work_dir.run_jj([ 471 "diff", 472 "--types", 473 &format!(r#"--from=description("{from}")"#), 474 &format!(r#"--to=description("{to}")"#), 475 ]) 476 }; 477 insta::assert_snapshot!(diff("missing", "file"), @r" 478 -F foo 479 [EOF] 480 "); 481 insta::assert_snapshot!(diff("file", "conflict"), @r" 482 FC foo 483 [EOF] 484 "); 485 insta::assert_snapshot!(diff("conflict", "missing"), @r" 486 C- foo 487 [EOF] 488 "); 489 490 #[cfg(unix)] 491 { 492 insta::assert_snapshot!(diff("symlink", "file"), @r" 493 LF foo 494 [EOF] 495 "); 496 insta::assert_snapshot!(diff("missing", "executable"), @r" 497 -F foo 498 [EOF] 499 "); 500 } 501} 502 503#[test] 504fn test_diff_name_only() { 505 let test_env = TestEnvironment::default(); 506 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 507 let work_dir = test_env.work_dir("repo"); 508 509 work_dir.run_jj(["new"]).success(); 510 work_dir.write_file("deleted", "d"); 511 work_dir.write_file("modified", "m"); 512 insta::assert_snapshot!(work_dir.run_jj(["diff", "--name-only"]), @r" 513 deleted 514 modified 515 [EOF] 516 "); 517 work_dir.run_jj(["commit", "-mfirst"]).success(); 518 work_dir.remove_file("deleted"); 519 work_dir.write_file("modified", "mod"); 520 work_dir.write_file("added", "add"); 521 work_dir.create_dir("sub"); 522 work_dir.write_file("sub/added", "sub/add"); 523 insta::assert_snapshot!(work_dir.run_jj(["diff", "--name-only"]).normalize_backslash(), @r" 524 added 525 deleted 526 modified 527 sub/added 528 [EOF] 529 "); 530} 531 532#[test] 533fn test_diff_bad_args() { 534 let test_env = TestEnvironment::default(); 535 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 536 let work_dir = test_env.work_dir("repo"); 537 538 let output = work_dir.run_jj(["diff", "-s", "--types"]); 539 insta::assert_snapshot!(output, @r" 540 ------- stderr ------- 541 error: the argument '--summary' cannot be used with '--types' 542 543 Usage: jj diff --summary [FILESETS]... 544 545 For more information, try '--help'. 546 [EOF] 547 [exit status: 2] 548 "); 549 550 let output = work_dir.run_jj(["diff", "--color-words", "--git"]); 551 insta::assert_snapshot!(output, @r" 552 ------- stderr ------- 553 error: the argument '--color-words' cannot be used with '--git' 554 555 Usage: jj diff --color-words [FILESETS]... 556 557 For more information, try '--help'. 558 [EOF] 559 [exit status: 2] 560 "); 561} 562 563#[test] 564fn test_diff_relative_paths() { 565 let test_env = TestEnvironment::default(); 566 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 567 let work_dir = test_env.work_dir("repo"); 568 569 work_dir.create_dir_all("dir1/subdir1"); 570 work_dir.create_dir("dir2"); 571 work_dir.write_file("file1", "foo1\n"); 572 work_dir.write_file("dir1/file2", "foo2\n"); 573 work_dir.write_file("dir1/subdir1/file3", "foo3\n"); 574 work_dir.write_file("dir2/file4", "foo4\n"); 575 work_dir.run_jj(["new"]).success(); 576 work_dir.write_file("file1", "bar1\n"); 577 work_dir.write_file("dir1/file2", "bar2\n"); 578 work_dir.write_file("dir1/subdir1/file3", "bar3\n"); 579 work_dir.write_file("dir2/file4", "bar4\n"); 580 581 let sub_dir1 = work_dir.dir("dir1"); 582 let output = sub_dir1.run_jj(["diff"]); 583 #[cfg(unix)] 584 insta::assert_snapshot!(output, @r" 585 Modified regular file file2: 586 1 1: foo2bar2 587 Modified regular file subdir1/file3: 588 1 1: foo3bar3 589 Modified regular file ../dir2/file4: 590 1 1: foo4bar4 591 Modified regular file ../file1: 592 1 1: foo1bar1 593 [EOF] 594 "); 595 #[cfg(windows)] 596 insta::assert_snapshot!(output, @r" 597 Modified regular file file2: 598 1 1: foo2bar2 599 Modified regular file subdir1\file3: 600 1 1: foo3bar3 601 Modified regular file ..\dir2\file4: 602 1 1: foo4bar4 603 Modified regular file ..\file1: 604 1 1: foo1bar1 605 [EOF] 606 "); 607 608 let output = sub_dir1.run_jj(["diff", "-s"]); 609 #[cfg(unix)] 610 insta::assert_snapshot!(output, @r" 611 M file2 612 M subdir1/file3 613 M ../dir2/file4 614 M ../file1 615 [EOF] 616 "); 617 #[cfg(windows)] 618 insta::assert_snapshot!(output, @r" 619 M file2 620 M subdir1\file3 621 M ..\dir2\file4 622 M ..\file1 623 [EOF] 624 "); 625 626 let output = sub_dir1.run_jj(["diff", "--types"]); 627 #[cfg(unix)] 628 insta::assert_snapshot!(output, @r" 629 FF file2 630 FF subdir1/file3 631 FF ../dir2/file4 632 FF ../file1 633 [EOF] 634 "); 635 #[cfg(windows)] 636 insta::assert_snapshot!(output, @r" 637 FF file2 638 FF subdir1\file3 639 FF ..\dir2\file4 640 FF ..\file1 641 [EOF] 642 "); 643 644 let output = sub_dir1.run_jj(["diff", "--git"]); 645 insta::assert_snapshot!(output, @r" 646 diff --git a/dir1/file2 b/dir1/file2 647 index 54b060eee9..1fe912cdd8 100644 648 --- a/dir1/file2 649 +++ b/dir1/file2 650 @@ -1,1 +1,1 @@ 651 -foo2 652 +bar2 653 diff --git a/dir1/subdir1/file3 b/dir1/subdir1/file3 654 index c1ec6c6f12..f3c8b75ec6 100644 655 --- a/dir1/subdir1/file3 656 +++ b/dir1/subdir1/file3 657 @@ -1,1 +1,1 @@ 658 -foo3 659 +bar3 660 diff --git a/dir2/file4 b/dir2/file4 661 index a0016dbc4c..17375f7a12 100644 662 --- a/dir2/file4 663 +++ b/dir2/file4 664 @@ -1,1 +1,1 @@ 665 -foo4 666 +bar4 667 diff --git a/file1 b/file1 668 index 1715acd6a5..05c4fe6772 100644 669 --- a/file1 670 +++ b/file1 671 @@ -1,1 +1,1 @@ 672 -foo1 673 +bar1 674 [EOF] 675 "); 676 677 let output = sub_dir1.run_jj(["diff", "--stat"]); 678 #[cfg(unix)] 679 insta::assert_snapshot!(output, @r" 680 file2 | 2 +- 681 subdir1/file3 | 2 +- 682 ../dir2/file4 | 2 +- 683 ../file1 | 2 +- 684 4 files changed, 4 insertions(+), 4 deletions(-) 685 [EOF] 686 "); 687 #[cfg(windows)] 688 insta::assert_snapshot!(output, @r" 689 file2 | 2 +- 690 subdir1\file3 | 2 +- 691 ..\dir2\file4 | 2 +- 692 ..\file1 | 2 +- 693 4 files changed, 4 insertions(+), 4 deletions(-) 694 [EOF] 695 "); 696} 697 698#[test] 699fn test_diff_hunks() { 700 let test_env = TestEnvironment::default(); 701 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 702 let work_dir = test_env.work_dir("repo"); 703 704 // Test added, removed, inserted, and modified lines. The modified line 705 // contains unchanged words. 706 work_dir.write_file("file1", ""); 707 work_dir.write_file("file2", "foo\n"); 708 work_dir.write_file("file3", "foo\nbaz qux blah blah\n"); 709 work_dir.run_jj(["new"]).success(); 710 work_dir.write_file("file1", "foo\n"); 711 work_dir.write_file("file2", ""); 712 work_dir.write_file("file3", "foo\nbar\nbaz quux blah blah\n"); 713 714 let output = work_dir.run_jj(["diff"]); 715 insta::assert_snapshot!(output, @r" 716 Modified regular file file1: 717 1: foo 718 Modified regular file file2: 719 1 : foo 720 Modified regular file file3: 721 1 1: foo 722 2: bar 723 2 3: baz quxquux blah blah 724 [EOF] 725 "); 726 727 let output = work_dir.run_jj(["diff", "--color=debug"]); 728 insta::assert_snapshot!(output, @r" 729 <<diff header::Modified regular file file1:>> 730 <<diff:: >><<diff added line_number:: 1>><<diff::: >><<diff added token::foo>> 731 <<diff header::Modified regular file file2:>> 732 <<diff removed line_number:: 1>><<diff:: : >><<diff removed token::foo>> 733 <<diff header::Modified regular file file3:>> 734 <<diff removed line_number:: 1>><<diff:: >><<diff added line_number:: 1>><<diff::: foo>> 735 <<diff:: >><<diff added line_number:: 2>><<diff::: >><<diff added token::bar>> 736 <<diff removed line_number:: 2>><<diff:: >><<diff added line_number:: 3>><<diff::: baz >><<diff removed token::qux>><<diff added token::quux>><<diff:: blah blah>> 737 [EOF] 738 "); 739 740 let output = work_dir.run_jj(["diff", "--git"]); 741 insta::assert_snapshot!(output, @r" 742 diff --git a/file1 b/file1 743 index e69de29bb2..257cc5642c 100644 744 --- a/file1 745 +++ b/file1 746 @@ -0,0 +1,1 @@ 747 +foo 748 diff --git a/file2 b/file2 749 index 257cc5642c..e69de29bb2 100644 750 --- a/file2 751 +++ b/file2 752 @@ -1,1 +0,0 @@ 753 -foo 754 diff --git a/file3 b/file3 755 index 221a95a095..a543ef3892 100644 756 --- a/file3 757 +++ b/file3 758 @@ -1,2 +1,3 @@ 759 foo 760 -baz qux blah blah 761 +bar 762 +baz quux blah blah 763 [EOF] 764 "); 765 766 let output = work_dir.run_jj(["diff", "--git", "--color=debug"]); 767 insta::assert_snapshot!(output, @r" 768 <<diff file_header::diff --git a/file1 b/file1>> 769 <<diff file_header::index e69de29bb2..257cc5642c 100644>> 770 <<diff file_header::--- a/file1>> 771 <<diff file_header::+++ b/file1>> 772 <<diff hunk_header::@@ -0,0 +1,1 @@>> 773 <<diff added::+>><<diff added token::foo>> 774 <<diff file_header::diff --git a/file2 b/file2>> 775 <<diff file_header::index 257cc5642c..e69de29bb2 100644>> 776 <<diff file_header::--- a/file2>> 777 <<diff file_header::+++ b/file2>> 778 <<diff hunk_header::@@ -1,1 +0,0 @@>> 779 <<diff removed::->><<diff removed token::foo>> 780 <<diff file_header::diff --git a/file3 b/file3>> 781 <<diff file_header::index 221a95a095..a543ef3892 100644>> 782 <<diff file_header::--- a/file3>> 783 <<diff file_header::+++ b/file3>> 784 <<diff hunk_header::@@ -1,2 +1,3 @@>> 785 <<diff context:: foo>> 786 <<diff removed::-baz >><<diff removed token::qux>><<diff removed:: blah blah>> 787 <<diff added::+>><<diff added token::bar>> 788 <<diff added::+baz >><<diff added token::quux>><<diff added:: blah blah>> 789 [EOF] 790 "); 791} 792 793#[test] 794fn test_diff_color_words_inlining_threshold() { 795 let test_env = TestEnvironment::default(); 796 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 797 let work_dir = test_env.work_dir("repo"); 798 799 let render_diff = |max_alternation: i32, args: &[&str]| { 800 let config = format!("diff.color-words.max-inline-alternation={max_alternation}"); 801 work_dir.run_jj_with(|cmd| cmd.args(["diff", "--config", &config]).args(args)) 802 }; 803 804 let file1_path = "file1-single-line"; 805 let file2_path = "file2-multiple-lines-in-single-hunk"; 806 let file3_path = "file3-changes-across-lines"; 807 work_dir.write_file( 808 file1_path, 809 indoc! {" 810 == adds == 811 a b c 812 == removes == 813 a b c d e f g 814 == adds + removes == 815 a b c d e 816 == adds + removes + adds == 817 a b c d e 818 == adds + removes + adds + removes == 819 a b c d e f g 820 "}, 821 ); 822 work_dir.write_file( 823 file2_path, 824 indoc! {" 825 == adds; removes; adds + removes == 826 a b c 827 a b c d e f g 828 a b c d e 829 == adds + removes + adds; adds + removes + adds + removes == 830 a b c d e 831 a b c d e f g 832 "}, 833 ); 834 work_dir.write_file( 835 file3_path, 836 indoc! {" 837 == adds == 838 a b c 839 == removes == 840 a b c d 841 e f g 842 == adds + removes == 843 a b c 844 d e 845 == adds + removes + adds == 846 a b c 847 d e 848 == adds + removes + adds + removes == 849 a b 850 c d e f g 851 "}, 852 ); 853 work_dir.run_jj(["new"]).success(); 854 work_dir.write_file( 855 file1_path, 856 indoc! {" 857 == adds == 858 a X b Y Z c 859 == removes == 860 a c f 861 == adds + removes == 862 a X b d 863 == adds + removes + adds == 864 a X b d Y 865 == adds + removes + adds + removes == 866 X a Y b d Z e 867 "}, 868 ); 869 work_dir.write_file( 870 file2_path, 871 indoc! {" 872 == adds; removes; adds + removes == 873 a X b Y Z c 874 a c f 875 a X b d 876 == adds + removes + adds; adds + removes + adds + removes == 877 a X b d Y 878 X a Y b d Z e 879 "}, 880 ); 881 work_dir.write_file( 882 file3_path, 883 indoc! {" 884 == adds == 885 a X b 886 Y Z c 887 == removes == 888 a c f 889 == adds + removes == 890 a 891 X b d 892 == adds + removes + adds == 893 a X b d 894 Y 895 == adds + removes + adds + removes == 896 X a Y b d 897 Z e 898 "}, 899 ); 900 901 // default 902 let output = work_dir.run_jj(["diff"]); 903 insta::assert_snapshot!(output, @r" 904 Modified regular file file1-single-line: 905 1 1: == adds == 906 2 2: a X b Y Z c 907 3 3: == removes == 908 4 4: a b c d e f g 909 5 5: == adds + removes == 910 6 6: a X b c d e 911 7 7: == adds + removes + adds == 912 8 8: a X b c d eY 913 9 9: == adds + removes + adds + removes == 914 10 : a b c d e f g 915 10: X a Y b d Z e 916 Modified regular file file2-multiple-lines-in-single-hunk: 917 1 1: == adds; removes; adds + removes == 918 2 2: a X b Y Z c 919 3 3: a b c d e f g 920 4 4: a X b c d e 921 5 5: == adds + removes + adds; adds + removes + adds + removes == 922 6 : a b c d e 923 7 : a b c d e f g 924 6: a X b d Y 925 7: X a Y b d Z e 926 Modified regular file file3-changes-across-lines: 927 1 1: == adds == 928 2 2: a X b 929 2 3: Y Z c 930 3 4: == removes == 931 4 5: a b c d 932 5 5: e f g 933 6 6: == adds + removes == 934 7 7: a 935 7 8: X b c 936 8 8: d e 937 9 9: == adds + removes + adds == 938 10 10: a X b c 939 11 10: d e 940 11 11: Y 941 12 12: == adds + removes + adds + removes == 942 13 : a b 943 14 : c d e f g 944 13: X a Y b d 945 14: Z e 946 [EOF] 947 "); 948 949 // -1: inline all 950 insta::assert_snapshot!(render_diff(-1, &[]), @r" 951 Modified regular file file1-single-line: 952 1 1: == adds == 953 2 2: a X b Y Z c 954 3 3: == removes == 955 4 4: a b c d e f g 956 5 5: == adds + removes == 957 6 6: a X b c d e 958 7 7: == adds + removes + adds == 959 8 8: a X b c d eY 960 9 9: == adds + removes + adds + removes == 961 10 10: X a Y b c d Z e f g 962 Modified regular file file2-multiple-lines-in-single-hunk: 963 1 1: == adds; removes; adds + removes == 964 2 2: a X b Y Z c 965 3 3: a b c d e f g 966 4 4: a X b c d e 967 5 5: == adds + removes + adds; adds + removes + adds + removes == 968 6 6: a X b c d eY 969 7 7: X a Y b c d Z e f g 970 Modified regular file file3-changes-across-lines: 971 1 1: == adds == 972 2 2: a X b 973 2 3: Y Z c 974 3 4: == removes == 975 4 5: a b c d 976 5 5: e f g 977 6 6: == adds + removes == 978 7 7: a 979 7 8: X b c 980 8 8: d e 981 9 9: == adds + removes + adds == 982 10 10: a X b c 983 11 10: d e 984 11 11: Y 985 12 12: == adds + removes + adds + removes == 986 13 13: X a Y b 987 14 13: c d 988 14 14: Z e f g 989 [EOF] 990 "); 991 992 // 0: no inlining 993 insta::assert_snapshot!(render_diff(0, &[]), @r" 994 Modified regular file file1-single-line: 995 1 1: == adds == 996 2 : a b c 997 2: a X b Y Z c 998 3 3: == removes == 999 4 : a b c d e f g 1000 4: a c f 1001 5 5: == adds + removes == 1002 6 : a b c d e 1003 6: a X b d 1004 7 7: == adds + removes + adds == 1005 8 : a b c d e 1006 8: a X b d Y 1007 9 9: == adds + removes + adds + removes == 1008 10 : a b c d e f g 1009 10: X a Y b d Z e 1010 Modified regular file file2-multiple-lines-in-single-hunk: 1011 1 1: == adds; removes; adds + removes == 1012 2 : a b c 1013 3 : a b c d e f g 1014 4 : a b c d e 1015 2: a X b Y Z c 1016 3: a c f 1017 4: a X b d 1018 5 5: == adds + removes + adds; adds + removes + adds + removes == 1019 6 : a b c d e 1020 7 : a b c d e f g 1021 6: a X b d Y 1022 7: X a Y b d Z e 1023 Modified regular file file3-changes-across-lines: 1024 1 1: == adds == 1025 2 : a b c 1026 2: a X b 1027 3: Y Z c 1028 3 4: == removes == 1029 4 : a b c d 1030 5 : e f g 1031 5: a c f 1032 6 6: == adds + removes == 1033 7 : a b c 1034 8 : d e 1035 7: a 1036 8: X b d 1037 9 9: == adds + removes + adds == 1038 10 : a b c 1039 11 : d e 1040 10: a X b d 1041 11: Y 1042 12 12: == adds + removes + adds + removes == 1043 13 : a b 1044 14 : c d e f g 1045 13: X a Y b d 1046 14: Z e 1047 [EOF] 1048 "); 1049 1050 // 1: inline adds-only or removes-only lines 1051 insta::assert_snapshot!(render_diff(1, &[]), @r" 1052 Modified regular file file1-single-line: 1053 1 1: == adds == 1054 2 2: a X b Y Z c 1055 3 3: == removes == 1056 4 4: a b c d e f g 1057 5 5: == adds + removes == 1058 6 : a b c d e 1059 6: a X b d 1060 7 7: == adds + removes + adds == 1061 8 : a b c d e 1062 8: a X b d Y 1063 9 9: == adds + removes + adds + removes == 1064 10 : a b c d e f g 1065 10: X a Y b d Z e 1066 Modified regular file file2-multiple-lines-in-single-hunk: 1067 1 1: == adds; removes; adds + removes == 1068 2 : a b c 1069 3 : a b c d e f g 1070 4 : a b c d e 1071 2: a X b Y Z c 1072 3: a c f 1073 4: a X b d 1074 5 5: == adds + removes + adds; adds + removes + adds + removes == 1075 6 : a b c d e 1076 7 : a b c d e f g 1077 6: a X b d Y 1078 7: X a Y b d Z e 1079 Modified regular file file3-changes-across-lines: 1080 1 1: == adds == 1081 2 2: a X b 1082 2 3: Y Z c 1083 3 4: == removes == 1084 4 5: a b c d 1085 5 5: e f g 1086 6 6: == adds + removes == 1087 7 : a b c 1088 8 : d e 1089 7: a 1090 8: X b d 1091 9 9: == adds + removes + adds == 1092 10 : a b c 1093 11 : d e 1094 10: a X b d 1095 11: Y 1096 12 12: == adds + removes + adds + removes == 1097 13 : a b 1098 14 : c d e f g 1099 13: X a Y b d 1100 14: Z e 1101 [EOF] 1102 "); 1103 1104 // 2: inline up to adds + removes lines 1105 insta::assert_snapshot!(render_diff(2, &[]), @r" 1106 Modified regular file file1-single-line: 1107 1 1: == adds == 1108 2 2: a X b Y Z c 1109 3 3: == removes == 1110 4 4: a b c d e f g 1111 5 5: == adds + removes == 1112 6 6: a X b c d e 1113 7 7: == adds + removes + adds == 1114 8 : a b c d e 1115 8: a X b d Y 1116 9 9: == adds + removes + adds + removes == 1117 10 : a b c d e f g 1118 10: X a Y b d Z e 1119 Modified regular file file2-multiple-lines-in-single-hunk: 1120 1 1: == adds; removes; adds + removes == 1121 2 2: a X b Y Z c 1122 3 3: a b c d e f g 1123 4 4: a X b c d e 1124 5 5: == adds + removes + adds; adds + removes + adds + removes == 1125 6 : a b c d e 1126 7 : a b c d e f g 1127 6: a X b d Y 1128 7: X a Y b d Z e 1129 Modified regular file file3-changes-across-lines: 1130 1 1: == adds == 1131 2 2: a X b 1132 2 3: Y Z c 1133 3 4: == removes == 1134 4 5: a b c d 1135 5 5: e f g 1136 6 6: == adds + removes == 1137 7 7: a 1138 7 8: X b c 1139 8 8: d e 1140 9 9: == adds + removes + adds == 1141 10 : a b c 1142 11 : d e 1143 10: a X b d 1144 11: Y 1145 12 12: == adds + removes + adds + removes == 1146 13 : a b 1147 14 : c d e f g 1148 13: X a Y b d 1149 14: Z e 1150 [EOF] 1151 "); 1152 1153 // 3: inline up to adds + removes + adds lines 1154 insta::assert_snapshot!(render_diff(3, &[]), @r" 1155 Modified regular file file1-single-line: 1156 1 1: == adds == 1157 2 2: a X b Y Z c 1158 3 3: == removes == 1159 4 4: a b c d e f g 1160 5 5: == adds + removes == 1161 6 6: a X b c d e 1162 7 7: == adds + removes + adds == 1163 8 8: a X b c d eY 1164 9 9: == adds + removes + adds + removes == 1165 10 : a b c d e f g 1166 10: X a Y b d Z e 1167 Modified regular file file2-multiple-lines-in-single-hunk: 1168 1 1: == adds; removes; adds + removes == 1169 2 2: a X b Y Z c 1170 3 3: a b c d e f g 1171 4 4: a X b c d e 1172 5 5: == adds + removes + adds; adds + removes + adds + removes == 1173 6 : a b c d e 1174 7 : a b c d e f g 1175 6: a X b d Y 1176 7: X a Y b d Z e 1177 Modified regular file file3-changes-across-lines: 1178 1 1: == adds == 1179 2 2: a X b 1180 2 3: Y Z c 1181 3 4: == removes == 1182 4 5: a b c d 1183 5 5: e f g 1184 6 6: == adds + removes == 1185 7 7: a 1186 7 8: X b c 1187 8 8: d e 1188 9 9: == adds + removes + adds == 1189 10 10: a X b c 1190 11 10: d e 1191 11 11: Y 1192 12 12: == adds + removes + adds + removes == 1193 13 : a b 1194 14 : c d e f g 1195 13: X a Y b d 1196 14: Z e 1197 [EOF] 1198 "); 1199 1200 // 4: inline up to adds + removes + adds + removes lines 1201 insta::assert_snapshot!(render_diff(4, &[]), @r" 1202 Modified regular file file1-single-line: 1203 1 1: == adds == 1204 2 2: a X b Y Z c 1205 3 3: == removes == 1206 4 4: a b c d e f g 1207 5 5: == adds + removes == 1208 6 6: a X b c d e 1209 7 7: == adds + removes + adds == 1210 8 8: a X b c d eY 1211 9 9: == adds + removes + adds + removes == 1212 10 10: X a Y b c d Z e f g 1213 Modified regular file file2-multiple-lines-in-single-hunk: 1214 1 1: == adds; removes; adds + removes == 1215 2 2: a X b Y Z c 1216 3 3: a b c d e f g 1217 4 4: a X b c d e 1218 5 5: == adds + removes + adds; adds + removes + adds + removes == 1219 6 6: a X b c d eY 1220 7 7: X a Y b c d Z e f g 1221 Modified regular file file3-changes-across-lines: 1222 1 1: == adds == 1223 2 2: a X b 1224 2 3: Y Z c 1225 3 4: == removes == 1226 4 5: a b c d 1227 5 5: e f g 1228 6 6: == adds + removes == 1229 7 7: a 1230 7 8: X b c 1231 8 8: d e 1232 9 9: == adds + removes + adds == 1233 10 10: a X b c 1234 11 10: d e 1235 11 11: Y 1236 12 12: == adds + removes + adds + removes == 1237 13 13: X a Y b 1238 14 13: c d 1239 14 14: Z e f g 1240 [EOF] 1241 "); 1242 1243 // context words in added/removed lines should be labeled as such 1244 insta::assert_snapshot!(render_diff(2, &["--color=always"]), @r" 1245 Modified regular file file1-single-line: 1246  1  1: == adds == 1247  2  2: a X b Y Z c 1248  3  3: == removes == 1249  4  4: a b c d e f g 1250  5  5: == adds + removes == 1251  6  6: a X b c d e 1252  7  7: == adds + removes + adds == 1253  8 : a b c d e 1254  8: a X b d Y 1255  9  9: == adds + removes + adds + removes == 1256  10 : a b c d e f g 1257  10: X a Y b d Z e 1258 Modified regular file file2-multiple-lines-in-single-hunk: 1259  1  1: == adds; removes; adds + removes == 1260  2  2: a X b Y Z c 1261  3  3: a b c d e f g 1262  4  4: a X b c d e 1263  5  5: == adds + removes + adds; adds + removes + adds + removes == 1264  6 : a b c d e 1265  7 : a b c d e f g 1266  6: a X b d Y 1267  7: X a Y b d Z e 1268 Modified regular file file3-changes-across-lines: 1269  1  1: == adds == 1270  2  2: a X b 1271  2  3: Y Z c 1272  3  4: == removes == 1273  4  5: a b c d 1274  5  5: e f g 1275  6  6: == adds + removes == 1276  7  7: a 1277  7  8: X b c 1278  8  8: d e 1279  9  9: == adds + removes + adds == 1280  10 : a b c 1281  11 : d e 1282  10: a X b d 1283  11: Y 1284  12  12: == adds + removes + adds + removes == 1285  13 : a b 1286  14 : c d e f g 1287  13: X a Y b d 1288  14: Z e 1289 [EOF] 1290 "); 1291 insta::assert_snapshot!(render_diff(2, &["--color=debug"]), @r" 1292 <<diff header::Modified regular file file1-single-line:>> 1293 <<diff removed line_number:: 1>><<diff:: >><<diff added line_number:: 1>><<diff::: == adds ==>> 1294 <<diff removed line_number:: 2>><<diff:: >><<diff added line_number:: 2>><<diff::: a >><<diff added token::X >><<diff::b >><<diff added token::Y Z >><<diff::c>> 1295 <<diff removed line_number:: 3>><<diff:: >><<diff added line_number:: 3>><<diff::: == removes ==>> 1296 <<diff removed line_number:: 4>><<diff:: >><<diff added line_number:: 4>><<diff::: a >><<diff removed token::b >><<diff::c >><<diff removed token::d e >><<diff::f>><<diff removed token:: g>><<diff::>> 1297 <<diff removed line_number:: 5>><<diff:: >><<diff added line_number:: 5>><<diff::: == adds + removes ==>> 1298 <<diff removed line_number:: 6>><<diff:: >><<diff added line_number:: 6>><<diff::: a >><<diff added token::X >><<diff::b >><<diff removed token::c >><<diff::d>><<diff removed token:: e>><<diff::>> 1299 <<diff removed line_number:: 7>><<diff:: >><<diff added line_number:: 7>><<diff::: == adds + removes + adds ==>> 1300 <<diff removed line_number:: 8>><<diff:: : >><<diff removed::a b >><<diff removed token::c >><<diff removed::d >><<diff removed token::e>><<diff removed::>> 1301 <<diff:: >><<diff added line_number:: 8>><<diff::: >><<diff added::a >><<diff added token::X >><<diff added::b d >><<diff added token::Y>><<diff added::>> 1302 <<diff removed line_number:: 9>><<diff:: >><<diff added line_number:: 9>><<diff::: == adds + removes + adds + removes ==>> 1303 <<diff removed line_number:: 10>><<diff:: : >><<diff removed::a b >><<diff removed token::c >><<diff removed::d e>><<diff removed token:: f g>><<diff removed::>> 1304 <<diff:: >><<diff added line_number:: 10>><<diff::: >><<diff added token::X >><<diff added::a >><<diff added token::Y >><<diff added::b d >><<diff added token::Z >><<diff added::e>> 1305 <<diff header::Modified regular file file2-multiple-lines-in-single-hunk:>> 1306 <<diff removed line_number:: 1>><<diff:: >><<diff added line_number:: 1>><<diff::: == adds; removes; adds + removes ==>> 1307 <<diff removed line_number:: 2>><<diff:: >><<diff added line_number:: 2>><<diff::: a >><<diff added token::X >><<diff::b >><<diff added token::Y Z >><<diff::c>> 1308 <<diff removed line_number:: 3>><<diff:: >><<diff added line_number:: 3>><<diff::: a >><<diff removed token::b >><<diff::c >><<diff removed token::d e >><<diff::f>><<diff removed token:: g>><<diff::>> 1309 <<diff removed line_number:: 4>><<diff:: >><<diff added line_number:: 4>><<diff::: a >><<diff added token::X >><<diff::b >><<diff removed token::c >><<diff::d>><<diff removed token:: e>><<diff::>> 1310 <<diff removed line_number:: 5>><<diff:: >><<diff added line_number:: 5>><<diff::: == adds + removes + adds; adds + removes + adds + removes ==>> 1311 <<diff removed line_number:: 6>><<diff:: : >><<diff removed::a b >><<diff removed token::c >><<diff removed::d >><<diff removed token::e>><<diff removed::>> 1312 <<diff removed line_number:: 7>><<diff:: : >><<diff removed::a b >><<diff removed token::c >><<diff removed::d e>><<diff removed token:: f g>><<diff removed::>> 1313 <<diff:: >><<diff added line_number:: 6>><<diff::: >><<diff added::a >><<diff added token::X >><<diff added::b d >><<diff added token::Y>><<diff added::>> 1314 <<diff:: >><<diff added line_number:: 7>><<diff::: >><<diff added token::X >><<diff added::a >><<diff added token::Y >><<diff added::b d >><<diff added token::Z >><<diff added::e>> 1315 <<diff header::Modified regular file file3-changes-across-lines:>> 1316 <<diff removed line_number:: 1>><<diff:: >><<diff added line_number:: 1>><<diff::: == adds ==>> 1317 <<diff removed line_number:: 2>><<diff:: >><<diff added line_number:: 2>><<diff::: a >><<diff added token::X >><<diff::b>><<diff added token::>> 1318 <<diff removed line_number:: 2>><<diff:: >><<diff added line_number:: 3>><<diff::: >><<diff added token::Y Z>><<diff:: c>> 1319 <<diff removed line_number:: 3>><<diff:: >><<diff added line_number:: 4>><<diff::: == removes ==>> 1320 <<diff removed line_number:: 4>><<diff:: >><<diff added line_number:: 5>><<diff::: a >><<diff removed token::b >><<diff::c >><<diff removed token::d>> 1321 <<diff removed line_number:: 5>><<diff:: >><<diff added line_number:: 5>><<diff::: >><<diff removed token::e >><<diff::f>><<diff removed token:: g>><<diff::>> 1322 <<diff removed line_number:: 6>><<diff:: >><<diff added line_number:: 6>><<diff::: == adds + removes ==>> 1323 <<diff removed line_number:: 7>><<diff:: >><<diff added line_number:: 7>><<diff::: a>><<diff added token::>> 1324 <<diff removed line_number:: 7>><<diff:: >><<diff added line_number:: 8>><<diff::: >><<diff added token::X>><<diff:: b >><<diff removed token::c>> 1325 <<diff removed line_number:: 8>><<diff:: >><<diff added line_number:: 8>><<diff::: d>><<diff removed token:: e>><<diff::>> 1326 <<diff removed line_number:: 9>><<diff:: >><<diff added line_number:: 9>><<diff::: == adds + removes + adds ==>> 1327 <<diff removed line_number:: 10>><<diff:: : >><<diff removed::a b >><<diff removed token::c>> 1328 <<diff removed line_number:: 11>><<diff:: : >><<diff removed::d>><<diff removed token:: e>><<diff removed::>> 1329 <<diff:: >><<diff added line_number:: 10>><<diff::: >><<diff added::a >><<diff added token::X >><<diff added::b d>><<diff added token::>> 1330 <<diff:: >><<diff added line_number:: 11>><<diff::: >><<diff added token::Y>><<diff added::>> 1331 <<diff removed line_number:: 12>><<diff:: >><<diff added line_number:: 12>><<diff::: == adds + removes + adds + removes ==>> 1332 <<diff removed line_number:: 13>><<diff:: : >><<diff removed::a b>><<diff removed token::>> 1333 <<diff removed line_number:: 14>><<diff:: : >><<diff removed token::c>><<diff removed:: d e>><<diff removed token:: f g>><<diff removed::>> 1334 <<diff:: >><<diff added line_number:: 13>><<diff::: >><<diff added token::X >><<diff added::a >><<diff added token::Y >><<diff added::b d>><<diff added token::>> 1335 <<diff:: >><<diff added line_number:: 14>><<diff::: >><<diff added token::Z>><<diff added:: e>> 1336 [EOF] 1337 "); 1338} 1339 1340#[test] 1341fn test_diff_missing_newline() { 1342 let test_env = TestEnvironment::default(); 1343 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1344 let work_dir = test_env.work_dir("repo"); 1345 1346 work_dir.write_file("file1", "foo"); 1347 work_dir.write_file("file2", "foo\nbar"); 1348 work_dir.run_jj(["new"]).success(); 1349 work_dir.write_file("file1", "foo\nbar"); 1350 work_dir.write_file("file2", "foo"); 1351 1352 let output = work_dir.run_jj(["diff"]); 1353 insta::assert_snapshot!(output, @r" 1354 Modified regular file file1: 1355 1 1: foo 1356 2: bar 1357 Modified regular file file2: 1358 1 1: foo 1359 2 : bar 1360 [EOF] 1361 "); 1362 1363 let output = work_dir.run_jj(["diff", "--git"]); 1364 insta::assert_snapshot!(output, @r" 1365 diff --git a/file1 b/file1 1366 index 1910281566..a907ec3f43 100644 1367 --- a/file1 1368 +++ b/file1 1369 @@ -1,1 +1,2 @@ 1370 -foo 1371 \ No newline at end of file 1372 +foo 1373 +bar 1374 \ No newline at end of file 1375 diff --git a/file2 b/file2 1376 index a907ec3f43..1910281566 100644 1377 --- a/file2 1378 +++ b/file2 1379 @@ -1,2 +1,1 @@ 1380 -foo 1381 -bar 1382 \ No newline at end of file 1383 +foo 1384 \ No newline at end of file 1385 [EOF] 1386 "); 1387 1388 let output = work_dir.run_jj(["diff", "--stat"]); 1389 insta::assert_snapshot!(output, @r" 1390 file1 | 3 ++- 1391 file2 | 3 +-- 1392 2 files changed, 3 insertions(+), 3 deletions(-) 1393 [EOF] 1394 "); 1395} 1396 1397#[test] 1398fn test_color_words_diff_missing_newline() { 1399 let test_env = TestEnvironment::default(); 1400 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1401 let work_dir = test_env.work_dir("repo"); 1402 1403 work_dir.write_file("file1", ""); 1404 work_dir.run_jj(["commit", "-m", "=== Empty"]).success(); 1405 work_dir.write_file("file1", "a\nb\nc\nd\ne\nf\ng\nh\ni"); 1406 work_dir 1407 .run_jj(["commit", "-m", "=== Add no newline"]) 1408 .success(); 1409 work_dir.write_file("file1", "A\nb\nc\nd\ne\nf\ng\nh\ni"); 1410 work_dir 1411 .run_jj(["commit", "-m", "=== Modify first line"]) 1412 .success(); 1413 work_dir.write_file("file1", "A\nb\nc\nd\nE\nf\ng\nh\ni"); 1414 work_dir 1415 .run_jj(["commit", "-m", "=== Modify middle line"]) 1416 .success(); 1417 work_dir.write_file("file1", "A\nb\nc\nd\nE\nf\ng\nh\nI"); 1418 work_dir 1419 .run_jj(["commit", "-m", "=== Modify last line"]) 1420 .success(); 1421 work_dir.write_file("file1", "A\nb\nc\nd\nE\nf\ng\nh\nI\n"); 1422 work_dir 1423 .run_jj(["commit", "-m", "=== Append newline"]) 1424 .success(); 1425 work_dir.write_file("file1", "A\nb\nc\nd\nE\nf\ng\nh\nI"); 1426 work_dir 1427 .run_jj(["commit", "-m", "=== Remove newline"]) 1428 .success(); 1429 work_dir.write_file("file1", ""); 1430 work_dir.run_jj(["commit", "-m", "=== Empty"]).success(); 1431 1432 let output = work_dir.run_jj([ 1433 "log", 1434 "-Tdescription", 1435 "-pr::@-", 1436 "--no-graph", 1437 "--reversed", 1438 ]); 1439 insta::assert_snapshot!(output, @r" 1440 === Empty 1441 Added regular file file1: 1442 (empty) 1443 === Add no newline 1444 Modified regular file file1: 1445 1: a 1446 2: b 1447 3: c 1448 4: d 1449 5: e 1450 6: f 1451 7: g 1452 8: h 1453 9: i 1454 === Modify first line 1455 Modified regular file file1: 1456 1 1: aA 1457 2 2: b 1458 3 3: c 1459 4 4: d 1460 ... 1461 === Modify middle line 1462 Modified regular file file1: 1463 1 1: A 1464 2 2: b 1465 3 3: c 1466 4 4: d 1467 5 5: eE 1468 6 6: f 1469 7 7: g 1470 8 8: h 1471 9 9: i 1472 === Modify last line 1473 Modified regular file file1: 1474 ... 1475 6 6: f 1476 7 7: g 1477 8 8: h 1478 9 9: iI 1479 === Append newline 1480 Modified regular file file1: 1481 ... 1482 6 6: f 1483 7 7: g 1484 8 8: h 1485 9 9: I 1486 === Remove newline 1487 Modified regular file file1: 1488 ... 1489 6 6: f 1490 7 7: g 1491 8 8: h 1492 9 9: I 1493 === Empty 1494 Modified regular file file1: 1495 1 : A 1496 2 : b 1497 3 : c 1498 4 : d 1499 5 : E 1500 6 : f 1501 7 : g 1502 8 : h 1503 9 : I 1504 [EOF] 1505 "); 1506 1507 let output = work_dir.run_jj([ 1508 "log", 1509 "--config=diff.color-words.max-inline-alternation=0", 1510 "-Tdescription", 1511 "-pr::@-", 1512 "--no-graph", 1513 "--reversed", 1514 ]); 1515 insta::assert_snapshot!(output, @r" 1516 === Empty 1517 Added regular file file1: 1518 (empty) 1519 === Add no newline 1520 Modified regular file file1: 1521 1: a 1522 2: b 1523 3: c 1524 4: d 1525 5: e 1526 6: f 1527 7: g 1528 8: h 1529 9: i 1530 === Modify first line 1531 Modified regular file file1: 1532 1 : a 1533 1: A 1534 2 2: b 1535 3 3: c 1536 4 4: d 1537 ... 1538 === Modify middle line 1539 Modified regular file file1: 1540 1 1: A 1541 2 2: b 1542 3 3: c 1543 4 4: d 1544 5 : e 1545 5: E 1546 6 6: f 1547 7 7: g 1548 8 8: h 1549 9 9: i 1550 === Modify last line 1551 Modified regular file file1: 1552 ... 1553 6 6: f 1554 7 7: g 1555 8 8: h 1556 9 : i 1557 9: I 1558 === Append newline 1559 Modified regular file file1: 1560 ... 1561 6 6: f 1562 7 7: g 1563 8 8: h 1564 9 : I 1565 9: I 1566 === Remove newline 1567 Modified regular file file1: 1568 ... 1569 6 6: f 1570 7 7: g 1571 8 8: h 1572 9 : I 1573 9: I 1574 === Empty 1575 Modified regular file file1: 1576 1 : A 1577 2 : b 1578 3 : c 1579 4 : d 1580 5 : E 1581 6 : f 1582 7 : g 1583 8 : h 1584 9 : I 1585 [EOF] 1586 "); 1587} 1588 1589#[test] 1590fn test_diff_ignore_whitespace() { 1591 let test_env = TestEnvironment::default(); 1592 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1593 let work_dir = test_env.work_dir("repo"); 1594 1595 work_dir.write_file( 1596 "file1", 1597 indoc! {" 1598 foo { 1599 bar; 1600 } 1601 baz {} 1602 "}, 1603 ); 1604 work_dir 1605 .run_jj(["new", "-mindent + whitespace insertion"]) 1606 .success(); 1607 work_dir.write_file( 1608 "file1", 1609 indoc! {" 1610 { 1611 foo { 1612 bar; 1613 } 1614 } 1615 baz { } 1616 "}, 1617 ); 1618 work_dir.run_jj(["status"]).success(); 1619 1620 // Git diff as reference output 1621 let output = work_dir.run_jj(["diff", "--git", "--ignore-all-space"]); 1622 insta::assert_snapshot!(output, @r" 1623 diff --git a/file1 b/file1 1624 index f532aa68ad..033c4a6168 100644 1625 --- a/file1 1626 +++ b/file1 1627 @@ -1,4 +1,6 @@ 1628 +{ 1629 foo { 1630 bar; 1631 } 1632 +} 1633 baz { } 1634 [EOF] 1635 "); 1636 let output = work_dir.run_jj(["diff", "--git", "--ignore-space-change"]); 1637 insta::assert_snapshot!(output, @r" 1638 diff --git a/file1 b/file1 1639 index f532aa68ad..033c4a6168 100644 1640 --- a/file1 1641 +++ b/file1 1642 @@ -1,4 +1,6 @@ 1643 -foo { 1644 +{ 1645 + foo { 1646 bar; 1647 + } 1648 } 1649 -baz {} 1650 +baz { } 1651 [EOF] 1652 "); 1653 1654 // Diff-stat should respects the whitespace options 1655 let output = work_dir.run_jj(["diff", "--stat", "--ignore-all-space"]); 1656 insta::assert_snapshot!(output, @r" 1657 file1 | 2 ++ 1658 1 file changed, 2 insertions(+), 0 deletions(-) 1659 [EOF] 1660 "); 1661 let output = work_dir.run_jj(["diff", "--stat", "--ignore-space-change"]); 1662 insta::assert_snapshot!(output, @r" 1663 file1 | 6 ++++-- 1664 1 file changed, 4 insertions(+), 2 deletions(-) 1665 [EOF] 1666 "); 1667 1668 // Word-level changes are still highlighted 1669 let output = work_dir.run_jj(["diff", "--color=always", "--ignore-all-space"]); 1670 insta::assert_snapshot!(output, @r" 1671 Modified regular file file1: 1672  1: { 1673  1  2:  foo { 1674  2  3:  bar; 1675  3  4:  } 1676  5: } 1677  4  6: baz { } 1678 [EOF] 1679 "); 1680 let output = work_dir.run_jj(["diff", "--color=always", "--ignore-space-change"]); 1681 insta::assert_snapshot!(output, @r" 1682 Modified regular file file1: 1683  1: { 1684  1  2:  foo { 1685  2  3:  bar; 1686  4:  } 1687  3  5: } 1688  4  6: baz { } 1689 [EOF] 1690 "); 1691} 1692 1693#[test] 1694fn test_diff_skipped_context() { 1695 let test_env = TestEnvironment::default(); 1696 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1697 let work_dir = test_env.work_dir("repo"); 1698 1699 work_dir.write_file("file1", "a\nb\nc\nd\ne\nf\ng\nh\ni\nj"); 1700 work_dir 1701 .run_jj(["describe", "-m", "=== Left side of diffs"]) 1702 .success(); 1703 1704 work_dir 1705 .run_jj(["new", "@", "-m", "=== Must skip 2 lines"]) 1706 .success(); 1707 work_dir.write_file("file1", "A\nb\nc\nd\ne\nf\ng\nh\ni\nJ"); 1708 work_dir 1709 .run_jj(["new", "@-", "-m", "=== Don't skip 1 line"]) 1710 .success(); 1711 work_dir.write_file("file1", "A\nb\nc\nd\ne\nf\ng\nh\nI\nj"); 1712 work_dir 1713 .run_jj(["new", "@-", "-m", "=== No gap to skip"]) 1714 .success(); 1715 work_dir.write_file("file1", "a\nB\nc\nd\ne\nf\ng\nh\nI\nj"); 1716 work_dir 1717 .run_jj(["new", "@-", "-m", "=== No gap to skip"]) 1718 .success(); 1719 work_dir.write_file("file1", "a\nb\nC\nd\ne\nf\ng\nh\nI\nj"); 1720 work_dir 1721 .run_jj(["new", "@-", "-m", "=== 1 line at start"]) 1722 .success(); 1723 work_dir.write_file("file1", "a\nb\nc\nd\nE\nf\ng\nh\ni\nj"); 1724 work_dir 1725 .run_jj(["new", "@-", "-m", "=== 1 line at end"]) 1726 .success(); 1727 work_dir.write_file("file1", "a\nb\nc\nd\ne\nF\ng\nh\ni\nj"); 1728 1729 let output = work_dir.run_jj(["log", "-Tdescription", "-p", "--no-graph", "--reversed"]); 1730 insta::assert_snapshot!(output, @r" 1731 === Left side of diffs 1732 Added regular file file1: 1733 1: a 1734 2: b 1735 3: c 1736 4: d 1737 5: e 1738 6: f 1739 7: g 1740 8: h 1741 9: i 1742 10: j 1743 === Must skip 2 lines 1744 Modified regular file file1: 1745 1 1: aA 1746 2 2: b 1747 3 3: c 1748 4 4: d 1749 ... 1750 7 7: g 1751 8 8: h 1752 9 9: i 1753 10 10: jJ 1754 === Don't skip 1 line 1755 Modified regular file file1: 1756 1 1: aA 1757 2 2: b 1758 3 3: c 1759 4 4: d 1760 5 5: e 1761 6 6: f 1762 7 7: g 1763 8 8: h 1764 9 9: iI 1765 10 10: j 1766 === No gap to skip 1767 Modified regular file file1: 1768 1 1: a 1769 2 2: bB 1770 3 3: c 1771 4 4: d 1772 5 5: e 1773 6 6: f 1774 7 7: g 1775 8 8: h 1776 9 9: iI 1777 10 10: j 1778 === No gap to skip 1779 Modified regular file file1: 1780 1 1: a 1781 2 2: b 1782 3 3: cC 1783 4 4: d 1784 5 5: e 1785 6 6: f 1786 7 7: g 1787 8 8: h 1788 9 9: iI 1789 10 10: j 1790 === 1 line at start 1791 Modified regular file file1: 1792 1 1: a 1793 2 2: b 1794 3 3: c 1795 4 4: d 1796 5 5: eE 1797 6 6: f 1798 7 7: g 1799 8 8: h 1800 ... 1801 === 1 line at end 1802 Modified regular file file1: 1803 ... 1804 3 3: c 1805 4 4: d 1806 5 5: e 1807 6 6: fF 1808 7 7: g 1809 8 8: h 1810 9 9: i 1811 10 10: j 1812 [EOF] 1813 "); 1814} 1815 1816#[test] 1817fn test_diff_skipped_context_from_settings_color_words() { 1818 let test_env = TestEnvironment::default(); 1819 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1820 let work_dir = test_env.work_dir("repo"); 1821 1822 test_env.add_config( 1823 r#" 1824[diff.color-words] 1825context = 0 1826 "#, 1827 ); 1828 1829 work_dir.write_file("file1", "a\nb\nc\nd\ne"); 1830 work_dir 1831 .run_jj(["describe", "-m", "=== First commit"]) 1832 .success(); 1833 1834 work_dir 1835 .run_jj(["new", "@", "-m", "=== Must show 0 context"]) 1836 .success(); 1837 work_dir.write_file("file1", "a\nb\nC\nd\ne"); 1838 1839 let output = work_dir.run_jj(["log", "-Tdescription", "-p", "--no-graph", "--reversed"]); 1840 insta::assert_snapshot!(output, @r" 1841 === First commit 1842 Added regular file file1: 1843 1: a 1844 2: b 1845 3: c 1846 4: d 1847 5: e 1848 === Must show 0 context 1849 Modified regular file file1: 1850 ... 1851 3 3: cC 1852 ... 1853 [EOF] 1854 "); 1855} 1856 1857#[test] 1858fn test_diff_skipped_context_from_settings_git() { 1859 let test_env = TestEnvironment::default(); 1860 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1861 let work_dir = test_env.work_dir("repo"); 1862 1863 test_env.add_config( 1864 r#" 1865[diff.git] 1866context = 0 1867 "#, 1868 ); 1869 1870 work_dir.write_file("file1", "a\nb\nc\nd\ne"); 1871 work_dir 1872 .run_jj(["describe", "-m", "=== First commit"]) 1873 .success(); 1874 1875 work_dir 1876 .run_jj(["new", "@", "-m", "=== Must show 0 context"]) 1877 .success(); 1878 work_dir.write_file("file1", "a\nb\nC\nd\ne"); 1879 1880 let output = work_dir.run_jj([ 1881 "log", 1882 "-Tdescription", 1883 "-p", 1884 "--git", 1885 "--no-graph", 1886 "--reversed", 1887 ]); 1888 insta::assert_snapshot!(output, @r" 1889 === First commit 1890 diff --git a/file1 b/file1 1891 new file mode 100644 1892 index 0000000000..0fec236860 1893 --- /dev/null 1894 +++ b/file1 1895 @@ -0,0 +1,5 @@ 1896 +a 1897 +b 1898 +c 1899 +d 1900 +e 1901 \ No newline at end of file 1902 === Must show 0 context 1903 diff --git a/file1 b/file1 1904 index 0fec236860..b7615dae52 100644 1905 --- a/file1 1906 +++ b/file1 1907 @@ -3,1 +3,1 @@ 1908 -c 1909 +C 1910 [EOF] 1911 "); 1912} 1913 1914#[test] 1915fn test_diff_skipped_context_nondefault() { 1916 let test_env = TestEnvironment::default(); 1917 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1918 let work_dir = test_env.work_dir("repo"); 1919 1920 work_dir.write_file("file1", "a\nb\nc\nd"); 1921 work_dir 1922 .run_jj(["describe", "-m", "=== Left side of diffs"]) 1923 .success(); 1924 1925 work_dir 1926 .run_jj(["new", "@", "-m", "=== Must skip 2 lines"]) 1927 .success(); 1928 work_dir.write_file("file1", "A\nb\nc\nD"); 1929 work_dir 1930 .run_jj(["new", "@-", "-m", "=== Don't skip 1 line"]) 1931 .success(); 1932 work_dir.write_file("file1", "A\nb\nC\nd"); 1933 work_dir 1934 .run_jj(["new", "@-", "-m", "=== No gap to skip"]) 1935 .success(); 1936 work_dir.write_file("file1", "a\nB\nC\nd"); 1937 work_dir 1938 .run_jj(["new", "@-", "-m", "=== 1 line at start"]) 1939 .success(); 1940 work_dir.write_file("file1", "a\nB\nc\nd"); 1941 work_dir 1942 .run_jj(["new", "@-", "-m", "=== 1 line at end"]) 1943 .success(); 1944 work_dir.write_file("file1", "a\nb\nC\nd"); 1945 1946 let output = work_dir.run_jj([ 1947 "log", 1948 "-Tdescription", 1949 "-p", 1950 "--no-graph", 1951 "--reversed", 1952 "--context=0", 1953 ]); 1954 insta::assert_snapshot!(output, @r" 1955 === Left side of diffs 1956 Added regular file file1: 1957 1: a 1958 2: b 1959 3: c 1960 4: d 1961 === Must skip 2 lines 1962 Modified regular file file1: 1963 1 1: aA 1964 ... 1965 4 4: dD 1966 === Don't skip 1 line 1967 Modified regular file file1: 1968 1 1: aA 1969 2 2: b 1970 3 3: cC 1971 4 4: d 1972 === No gap to skip 1973 Modified regular file file1: 1974 1 1: a 1975 2 2: bB 1976 3 3: cC 1977 4 4: d 1978 === 1 line at start 1979 Modified regular file file1: 1980 1 1: a 1981 2 2: bB 1982 ... 1983 === 1 line at end 1984 Modified regular file file1: 1985 ... 1986 3 3: cC 1987 4 4: d 1988 [EOF] 1989 "); 1990} 1991 1992#[test] 1993fn test_diff_leading_trailing_context() { 1994 let test_env = TestEnvironment::default(); 1995 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1996 let work_dir = test_env.work_dir("repo"); 1997 1998 // N=5 context lines at start/end of the file 1999 work_dir.write_file("file1", "1\n2\n3\n4\n5\nL\n6\n7\n8\n9\n10\n11\n"); 2000 work_dir.run_jj(["new"]).success(); 2001 work_dir.write_file("file1", "1\n2\n3\n4\n5\n6\nR\n7\n8\n9\n10\n11\n"); 2002 2003 // N=5 <= num_context_lines + 1: No room to skip. 2004 let output = work_dir.run_jj(["diff", "--context=4"]); 2005 insta::assert_snapshot!(output, @r" 2006 Modified regular file file1: 2007 1 1: 1 2008 2 2: 2 2009 3 3: 3 2010 4 4: 4 2011 5 5: 5 2012 6 : L 2013 7 6: 6 2014 7: R 2015 8 8: 7 2016 9 9: 8 2017 10 10: 9 2018 11 11: 10 2019 12 12: 11 2020 [EOF] 2021 "); 2022 2023 // N=5 <= 2 * num_context_lines + 1: The last hunk wouldn't be split if 2024 // trailing diff existed. 2025 let output = work_dir.run_jj(["diff", "--context=3"]); 2026 insta::assert_snapshot!(output, @r" 2027 Modified regular file file1: 2028 ... 2029 3 3: 3 2030 4 4: 4 2031 5 5: 5 2032 6 : L 2033 7 6: 6 2034 7: R 2035 8 8: 7 2036 9 9: 8 2037 10 10: 9 2038 ... 2039 [EOF] 2040 "); 2041 2042 // N=5 > 2 * num_context_lines + 1: The last hunk should be split no matter 2043 // if trailing diff existed. 2044 let output = work_dir.run_jj(["diff", "--context=1"]); 2045 insta::assert_snapshot!(output, @r" 2046 Modified regular file file1: 2047 ... 2048 5 5: 5 2049 6 : L 2050 7 6: 6 2051 7: R 2052 8 8: 7 2053 ... 2054 [EOF] 2055 "); 2056 2057 // N=5 <= num_context_lines: No room to skip. 2058 let output = work_dir.run_jj(["diff", "--git", "--context=5"]); 2059 insta::assert_snapshot!(output, @r" 2060 diff --git a/file1 b/file1 2061 index 1bf57dee4a..69b3e1865c 100644 2062 --- a/file1 2063 +++ b/file1 2064 @@ -1,12 +1,12 @@ 2065 1 2066 2 2067 3 2068 4 2069 5 2070 -L 2071 6 2072 +R 2073 7 2074 8 2075 9 2076 10 2077 11 2078 [EOF] 2079 "); 2080 2081 // N=5 <= 2 * num_context_lines: The last hunk wouldn't be split if 2082 // trailing diff existed. 2083 let output = work_dir.run_jj(["diff", "--git", "--context=3"]); 2084 insta::assert_snapshot!(output, @r" 2085 diff --git a/file1 b/file1 2086 index 1bf57dee4a..69b3e1865c 100644 2087 --- a/file1 2088 +++ b/file1 2089 @@ -3,8 +3,8 @@ 2090 3 2091 4 2092 5 2093 -L 2094 6 2095 +R 2096 7 2097 8 2098 9 2099 [EOF] 2100 "); 2101 2102 // N=5 > 2 * num_context_lines: The last hunk should be split no matter 2103 // if trailing diff existed. 2104 let output = work_dir.run_jj(["diff", "--git", "--context=2"]); 2105 insta::assert_snapshot!(output, @r" 2106 diff --git a/file1 b/file1 2107 index 1bf57dee4a..69b3e1865c 100644 2108 --- a/file1 2109 +++ b/file1 2110 @@ -4,6 +4,6 @@ 2111 4 2112 5 2113 -L 2114 6 2115 +R 2116 7 2117 8 2118 [EOF] 2119 "); 2120} 2121 2122#[test] 2123fn test_diff_external_tool() { 2124 let mut test_env = TestEnvironment::default(); 2125 let edit_script = test_env.set_up_fake_diff_editor(); 2126 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2127 let work_dir = test_env.work_dir("repo"); 2128 2129 work_dir.write_file("file1", "foo\n"); 2130 work_dir.write_file("file2", "foo\n"); 2131 work_dir.run_jj(["new"]).success(); 2132 work_dir.remove_file("file1"); 2133 work_dir.write_file("file2", "foo\nbar\n"); 2134 work_dir.write_file("file3", "foo\n"); 2135 2136 // nonzero exit codes should print a warning 2137 std::fs::write(&edit_script, "fail").unwrap(); 2138 let output = work_dir.run_jj(["diff", "--config=ui.diff.tool=fake-diff-editor"]); 2139 let mut insta_settings = insta::Settings::clone_current(); 2140 insta_settings.add_filter("exit (status|code)", "<exit status>"); 2141 insta_settings.bind(|| { 2142 insta::assert_snapshot!(output, @r" 2143 ------- stderr ------- 2144 Warning: Tool exited with <exit status>: 1 (run with --debug to see the exact invocation) 2145 [EOF] 2146 "); 2147 }); 2148 2149 // nonzero exit codes should not print a warning if it's an expected exit code 2150 std::fs::write(&edit_script, "fail").unwrap(); 2151 let output = work_dir.run_jj([ 2152 "diff", 2153 "--tool", 2154 "fake-diff-editor", 2155 "--config=merge-tools.fake-diff-editor.diff-expected-exit-codes=[1]", 2156 ]); 2157 insta::assert_snapshot!(output, @""); 2158 2159 std::fs::write( 2160 &edit_script, 2161 "print-files-before\0print --\0print-files-after", 2162 ) 2163 .unwrap(); 2164 2165 // diff without file patterns 2166 insta::assert_snapshot!(work_dir.run_jj(["diff", "--tool=fake-diff-editor"]), @r" 2167 file1 2168 file2 2169 -- 2170 file2 2171 file3 2172 [EOF] 2173 "); 2174 2175 // diff with file patterns 2176 insta::assert_snapshot!(work_dir.run_jj(["diff", "--tool=fake-diff-editor", "file1"]), @r" 2177 file1 2178 -- 2179 [EOF] 2180 "); 2181 2182 insta::assert_snapshot!(work_dir.run_jj(["log", "-p", "--tool=fake-diff-editor"]), @r" 2183 @ rlvkpnrz test.user@example.com 2001-02-03 08:05:09 39d9055d 2184 │ (no description set) 2185 │ file1 2186 │ file2 2187 │ -- 2188 │ file2 2189 │ file3 2190 ○ qpvuntsm test.user@example.com 2001-02-03 08:05:08 0ad4ef22 2191 │ (no description set) 2192 │ -- 2193 │ file1 2194 │ file2 2195 ◆ zzzzzzzz root() 00000000 2196 -- 2197 [EOF] 2198 "); 2199 2200 insta::assert_snapshot!(work_dir.run_jj(["show", "--tool=fake-diff-editor"]), @r" 2201 Commit ID: 39d9055d70873099fd924b9af218289d5663eac8 2202 Change ID: rlvkpnrzqnoowoytxnquwvuryrwnrmlp 2203 Author : Test User <test.user@example.com> (2001-02-03 08:05:09) 2204 Committer: Test User <test.user@example.com> (2001-02-03 08:05:09) 2205 2206 (no description set) 2207 2208 file1 2209 file2 2210 -- 2211 file2 2212 file3 2213 [EOF] 2214 "); 2215 2216 // Enabled by default, looks up the merge-tools table 2217 let config = "--config=ui.diff.tool=fake-diff-editor"; 2218 insta::assert_snapshot!(work_dir.run_jj(["diff", config]), @r" 2219 file1 2220 file2 2221 -- 2222 file2 2223 file3 2224 [EOF] 2225 "); 2226 2227 // Inlined command arguments 2228 let command_toml = to_toml_value(fake_diff_editor_path()); 2229 let config = format!("--config=ui.diff.tool=[{command_toml}, '$right', '$left']"); 2230 insta::assert_snapshot!(work_dir.run_jj(["diff", &config]), @r" 2231 file2 2232 file3 2233 -- 2234 file1 2235 file2 2236 [EOF] 2237 "); 2238 2239 // Output of external diff tool shouldn't be escaped 2240 std::fs::write(&edit_script, "print \x1b[1;31mred").unwrap(); 2241 insta::assert_snapshot!(work_dir.run_jj(["diff", "--color=always", "--tool=fake-diff-editor"]), 2242 @r" 2243 red 2244 [EOF] 2245 "); 2246 2247 // Non-zero exit code isn't an error 2248 std::fs::write(&edit_script, "print diff\0fail").unwrap(); 2249 let output = work_dir.run_jj(["show", "--tool=fake-diff-editor"]); 2250 insta::assert_snapshot!(output.normalize_stderr_exit_status(), @r" 2251 Commit ID: 39d9055d70873099fd924b9af218289d5663eac8 2252 Change ID: rlvkpnrzqnoowoytxnquwvuryrwnrmlp 2253 Author : Test User <test.user@example.com> (2001-02-03 08:05:09) 2254 Committer: Test User <test.user@example.com> (2001-02-03 08:05:09) 2255 2256 (no description set) 2257 2258 diff 2259 [EOF] 2260 ------- stderr ------- 2261 Warning: Tool exited with exit status: 1 (run with --debug to see the exact invocation) 2262 [EOF] 2263 "); 2264 2265 // --tool=:builtin shouldn't be ignored 2266 let output = work_dir.run_jj(["diff", "--tool=:builtin"]); 2267 insta::assert_snapshot!(output.strip_stderr_last_line(), @r" 2268 ------- stderr ------- 2269 Error: Failed to generate diff 2270 Caused by: 2271 1: Error executing ':builtin' (run with --debug to see the exact invocation) 2272 [EOF] 2273 [exit status: 1] 2274 "); 2275} 2276 2277#[test] 2278fn test_diff_external_file_by_file_tool() { 2279 let mut test_env = TestEnvironment::default(); 2280 let edit_script = test_env.set_up_fake_diff_editor(); 2281 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2282 let work_dir = test_env.work_dir("repo"); 2283 2284 work_dir.write_file("file1", "file1\n"); 2285 work_dir.write_file("file2", "file2\n"); 2286 work_dir.run_jj(["new"]).success(); 2287 work_dir.remove_file("file1"); 2288 work_dir.write_file("file2", "file2\nfile2\n"); 2289 work_dir.write_file("file3", "file3\n"); 2290 work_dir.write_file("file4", "file1\n"); 2291 2292 std::fs::write( 2293 edit_script, 2294 "print ==\0print-files-before\0print --\0print-files-after", 2295 ) 2296 .unwrap(); 2297 2298 // Enabled by default, looks up the merge-tools table 2299 let configs: &[_] = &[ 2300 "--config=ui.diff.tool=fake-diff-editor", 2301 "--config=merge-tools.fake-diff-editor.diff-invocation-mode=file-by-file", 2302 ]; 2303 2304 // diff without file patterns 2305 insta::assert_snapshot!(work_dir.run_jj_with(|cmd| cmd.arg("diff").args(configs)), @r" 2306 == 2307 file2 2308 -- 2309 file2 2310 == 2311 file3 2312 -- 2313 file3 2314 == 2315 file1 2316 -- 2317 file4 2318 [EOF] 2319 "); 2320 2321 // diff with file patterns 2322 insta::assert_snapshot!( 2323 work_dir.run_jj_with(|cmd| cmd.args(["diff", "file1"]).args(configs)), @r" 2324 == 2325 file1 2326 -- 2327 file1 2328 [EOF] 2329 "); 2330 insta::assert_snapshot!( 2331 work_dir.run_jj_with(|cmd| cmd.args(["log", "-p"]).args(configs)), @r" 2332 @ rlvkpnrz test.user@example.com 2001-02-03 08:05:09 7b01704a 2333 │ (no description set) 2334 │ == 2335 │ file2 2336 │ -- 2337 │ file2 2338 │ == 2339 │ file3 2340 │ -- 2341 │ file3 2342 │ == 2343 │ file1 2344 │ -- 2345 │ file4 2346 ○ qpvuntsm test.user@example.com 2001-02-03 08:05:08 6e485984 2347 │ (no description set) 2348 │ == 2349 │ file1 2350 │ -- 2351 │ file1 2352 │ == 2353 │ file2 2354 │ -- 2355 │ file2 2356 ◆ zzzzzzzz root() 00000000 2357 [EOF] 2358 "); 2359 2360 insta::assert_snapshot!(work_dir.run_jj_with(|cmd| cmd.arg("show").args(configs)), @r" 2361 Commit ID: 7b01704a670bc77d11ed117d362855cff1d4513b 2362 Change ID: rlvkpnrzqnoowoytxnquwvuryrwnrmlp 2363 Author : Test User <test.user@example.com> (2001-02-03 08:05:09) 2364 Committer: Test User <test.user@example.com> (2001-02-03 08:05:09) 2365 2366 (no description set) 2367 2368 == 2369 file2 2370 -- 2371 file2 2372 == 2373 file3 2374 -- 2375 file3 2376 == 2377 file1 2378 -- 2379 file4 2380 [EOF] 2381 "); 2382} 2383 2384#[cfg(unix)] 2385#[test] 2386fn test_diff_external_tool_symlink() { 2387 let mut test_env = TestEnvironment::default(); 2388 let edit_script = test_env.set_up_fake_diff_editor(); 2389 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2390 let work_dir = test_env.work_dir("repo"); 2391 2392 let external_file_path = test_env.env_root().join("external-file"); 2393 std::fs::write(&external_file_path, "").unwrap(); 2394 let external_file_permissions = external_file_path.symlink_metadata().unwrap().permissions(); 2395 2396 std::os::unix::fs::symlink("non-existent1", work_dir.root().join("dead")).unwrap(); 2397 std::os::unix::fs::symlink(&external_file_path, work_dir.root().join("file")).unwrap(); 2398 work_dir.run_jj(["new"]).success(); 2399 work_dir.remove_file("dead"); 2400 std::os::unix::fs::symlink("non-existent2", work_dir.root().join("dead")).unwrap(); 2401 work_dir.remove_file("file"); 2402 work_dir.write_file("file", ""); 2403 2404 std::fs::write( 2405 edit_script, 2406 "print-files-before\0print --\0print-files-after", 2407 ) 2408 .unwrap(); 2409 2410 // Shouldn't try to change permission of symlinks 2411 insta::assert_snapshot!(work_dir.run_jj(["diff", "--tool=fake-diff-editor"]), @r" 2412 dead 2413 file 2414 -- 2415 dead 2416 file 2417 [EOF] 2418 "); 2419 2420 // External file should be intact 2421 assert_eq!( 2422 external_file_path.symlink_metadata().unwrap().permissions(), 2423 external_file_permissions 2424 ); 2425} 2426 2427#[test] 2428fn test_diff_external_tool_conflict_marker_style() { 2429 let mut test_env = TestEnvironment::default(); 2430 let edit_script = test_env.set_up_fake_diff_editor(); 2431 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2432 let work_dir = test_env.work_dir("repo"); 2433 let file_path = "file"; 2434 2435 // Create a conflict 2436 work_dir.write_file( 2437 file_path, 2438 indoc! {" 2439 line 1 2440 line 2 2441 line 3 2442 line 4 2443 line 5 2444 "}, 2445 ); 2446 work_dir.run_jj(["commit", "-m", "base"]).success(); 2447 work_dir.write_file( 2448 file_path, 2449 indoc! {" 2450 line 1 2451 line 2.1 2452 line 2.2 2453 line 3 2454 line 4.1 2455 line 5 2456 "}, 2457 ); 2458 work_dir.run_jj(["describe", "-m", "side-a"]).success(); 2459 work_dir 2460 .run_jj(["new", "description(base)", "-m", "side-b"]) 2461 .success(); 2462 work_dir.write_file( 2463 file_path, 2464 indoc! {" 2465 line 1 2466 line 2.3 2467 line 3 2468 line 4.2 2469 line 4.3 2470 line 5 2471 "}, 2472 ); 2473 2474 // Resolve one of the conflicts in the working copy 2475 work_dir 2476 .run_jj(["new", "description(side-a)", "description(side-b)"]) 2477 .success(); 2478 work_dir.write_file( 2479 file_path, 2480 indoc! {" 2481 line 1 2482 line 2.1 2483 line 2.2 2484 line 2.3 2485 line 3 2486 <<<<<<< 2487 %%%%%%% 2488 -line 4 2489 +line 4.1 2490 +++++++ 2491 line 4.2 2492 line 4.3 2493 >>>>>>> 2494 line 5 2495 "}, 2496 ); 2497 2498 // Set up diff editor to use "snapshot" conflict markers 2499 test_env.add_config(r#"merge-tools.fake-diff-editor.conflict-marker-style = "snapshot""#); 2500 2501 // We want to see whether the diff is using the correct conflict markers 2502 std::fs::write( 2503 &edit_script, 2504 ["files-before file", "files-after file", "dump file file"].join("\0"), 2505 ) 2506 .unwrap(); 2507 let output = work_dir.run_jj(["diff", "--tool", "fake-diff-editor"]); 2508 insta::assert_snapshot!(output, @""); 2509 // Conflicts should render using "snapshot" format 2510 insta::assert_snapshot!( 2511 std::fs::read_to_string(test_env.env_root().join("file")).unwrap(), @r" 2512 line 1 2513 line 2.1 2514 line 2.2 2515 line 2.3 2516 line 3 2517 <<<<<<< Conflict 1 of 1 2518 +++++++ Contents of side #1 2519 line 4.1 2520 ------- Contents of base 2521 line 4 2522 +++++++ Contents of side #2 2523 line 4.2 2524 line 4.3 2525 >>>>>>> Conflict 1 of 1 ends 2526 line 5 2527 "); 2528} 2529 2530#[test] 2531fn test_diff_stat() { 2532 let test_env = TestEnvironment::default(); 2533 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2534 let work_dir = test_env.work_dir("repo"); 2535 work_dir.write_file("file1", "foo\n"); 2536 2537 let output = work_dir.run_jj(["diff", "--stat"]); 2538 insta::assert_snapshot!(output, @r" 2539 file1 | 1 + 2540 1 file changed, 1 insertion(+), 0 deletions(-) 2541 [EOF] 2542 "); 2543 2544 work_dir.run_jj(["new"]).success(); 2545 2546 let output = work_dir.run_jj(["diff", "--stat"]); 2547 insta::assert_snapshot!(output, @r" 2548 0 files changed, 0 insertions(+), 0 deletions(-) 2549 [EOF] 2550 "); 2551 2552 work_dir.write_file("file1", "foo\nbar\n"); 2553 work_dir.run_jj(["new"]).success(); 2554 work_dir.write_file("file1", "bar\n"); 2555 2556 let output = work_dir.run_jj(["diff", "--stat"]); 2557 insta::assert_snapshot!(output, @r" 2558 file1 | 1 - 2559 1 file changed, 0 insertions(+), 1 deletion(-) 2560 [EOF] 2561 "); 2562} 2563 2564#[test] 2565fn test_diff_stat_long_name_or_stat() { 2566 let mut test_env = TestEnvironment::default(); 2567 test_env.add_env_var("COLUMNS", "30"); 2568 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2569 let work_dir = test_env.work_dir("repo"); 2570 2571 let get_stat = |work_dir: &TestWorkDir, path_length: usize, stat_size: usize| { 2572 work_dir.run_jj(["new", "root()"]).success(); 2573 let ascii_name = "1234567890".chars().cycle().take(path_length).join(""); 2574 let han_name = "一二三四五六七八九十" 2575 .chars() 2576 .cycle() 2577 .take(path_length) 2578 .join(""); 2579 let content = "content line\n".repeat(stat_size); 2580 work_dir.write_file(ascii_name, &content); 2581 work_dir.write_file(han_name, &content); 2582 work_dir.run_jj(["diff", "--stat"]) 2583 }; 2584 2585 insta::assert_snapshot!(get_stat(&work_dir, 1, 1), @r" 2586 1 | 1 + 2587 一 | 1 + 2588 2 files changed, 2 insertions(+), 0 deletions(-) 2589 [EOF] 2590 "); 2591 insta::assert_snapshot!(get_stat(&work_dir, 1, 10), @r" 2592 1 | 10 ++++++++++ 2593 一 | 10 ++++++++++ 2594 2 files changed, 20 insertions(+), 0 deletions(-) 2595 [EOF] 2596 "); 2597 insta::assert_snapshot!(get_stat(&work_dir, 1, 100), @r" 2598 1 | 100 +++++++++++++++++ 2599 一 | 100 +++++++++++++++++ 2600 2 files changed, 200 insertions(+), 0 deletions(-) 2601 [EOF] 2602 "); 2603 insta::assert_snapshot!(get_stat(&work_dir, 10, 1), @r" 2604 1234567890 | 1 + 2605 ...五六七八九十 | 1 + 2606 2 files changed, 2 insertions(+), 0 deletions(-) 2607 [EOF] 2608 "); 2609 insta::assert_snapshot!(get_stat(&work_dir, 10, 10), @r" 2610 1234567890 | 10 +++++++ 2611 ...六七八九十 | 10 +++++++ 2612 2 files changed, 20 insertions(+), 0 deletions(-) 2613 [EOF] 2614 "); 2615 insta::assert_snapshot!(get_stat(&work_dir, 10, 100), @r" 2616 1234567890 | 100 ++++++ 2617 ...六七八九十 | 100 ++++++ 2618 2 files changed, 200 insertions(+), 0 deletions(-) 2619 [EOF] 2620 "); 2621 insta::assert_snapshot!(get_stat(&work_dir, 50, 1), @r" 2622 ...901234567890 | 1 + 2623 ...五六七八九十 | 1 + 2624 2 files changed, 2 insertions(+), 0 deletions(-) 2625 [EOF] 2626 "); 2627 insta::assert_snapshot!(get_stat(&work_dir, 50, 10), @r" 2628 ...01234567890 | 10 +++++++ 2629 ...六七八九十 | 10 +++++++ 2630 2 files changed, 20 insertions(+), 0 deletions(-) 2631 [EOF] 2632 "); 2633 insta::assert_snapshot!(get_stat(&work_dir, 50, 100), @r" 2634 ...01234567890 | 100 ++++++ 2635 ...六七八九十 | 100 ++++++ 2636 2 files changed, 200 insertions(+), 0 deletions(-) 2637 [EOF] 2638 "); 2639 2640 // Lengths around where we introduce the ellipsis 2641 insta::assert_snapshot!(get_stat(&work_dir, 13, 100), @r" 2642 1234567890123 | 100 ++++++ 2643 ...九十一二三 | 100 ++++++ 2644 2 files changed, 200 insertions(+), 0 deletions(-) 2645 [EOF] 2646 "); 2647 insta::assert_snapshot!(get_stat(&work_dir, 14, 100), @r" 2648 12345678901234 | 100 ++++++ 2649 ...十一二三四 | 100 ++++++ 2650 2 files changed, 200 insertions(+), 0 deletions(-) 2651 [EOF] 2652 "); 2653 insta::assert_snapshot!(get_stat(&work_dir, 15, 100), @r" 2654 ...56789012345 | 100 ++++++ 2655 ...一二三四五 | 100 ++++++ 2656 2 files changed, 200 insertions(+), 0 deletions(-) 2657 [EOF] 2658 "); 2659 insta::assert_snapshot!(get_stat(&work_dir, 16, 100), @r" 2660 ...67890123456 | 100 ++++++ 2661 ...二三四五六 | 100 ++++++ 2662 2 files changed, 200 insertions(+), 0 deletions(-) 2663 [EOF] 2664 "); 2665 2666 // Very narrow terminal (doesn't have to fit, just don't crash) 2667 test_env.add_env_var("COLUMNS", "10"); 2668 let work_dir = test_env.work_dir("repo"); 2669 insta::assert_snapshot!(get_stat(&work_dir, 10, 10), @r" 2670 ... | 10 ++ 2671 ... | 10 ++ 2672 2 files changed, 20 insertions(+), 0 deletions(-) 2673 [EOF] 2674 "); 2675 test_env.add_env_var("COLUMNS", "3"); 2676 let work_dir = test_env.work_dir("repo"); 2677 insta::assert_snapshot!(get_stat(&work_dir, 10, 10), @r" 2678 ... | 10 ++ 2679 ... | 10 ++ 2680 2 files changed, 20 insertions(+), 0 deletions(-) 2681 [EOF] 2682 "); 2683 insta::assert_snapshot!(get_stat(&work_dir, 3, 10), @r" 2684 123 | 10 ++ 2685 ... | 10 ++ 2686 2 files changed, 20 insertions(+), 0 deletions(-) 2687 [EOF] 2688 "); 2689 insta::assert_snapshot!(get_stat(&work_dir, 1, 10), @r" 2690 1 | 10 ++ 2691 一 | 10 ++ 2692 2 files changed, 20 insertions(+), 0 deletions(-) 2693 [EOF] 2694 "); 2695} 2696 2697#[test] 2698fn test_diff_binary() { 2699 let test_env = TestEnvironment::default(); 2700 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2701 let work_dir = test_env.work_dir("repo"); 2702 2703 work_dir.write_file("file1.png", b"\x89PNG\r\n\x1a\nabcdefg\0"); 2704 work_dir.write_file("file2.png", b"\x89PNG\r\n\x1a\n0123456\0"); 2705 work_dir.run_jj(["new"]).success(); 2706 work_dir.remove_file("file1.png"); 2707 work_dir.write_file("file2.png", "foo\nbar\n"); 2708 work_dir.write_file("file3.png", b"\x89PNG\r\n\x1a\nxyz\0"); 2709 // try a file that's valid UTF-8 but contains control characters 2710 work_dir.write_file("file4.png", b"\0\0\0"); 2711 2712 let output = work_dir.run_jj(["diff"]); 2713 insta::assert_snapshot!(output, @r" 2714 Removed regular file file1.png: 2715 (binary) 2716 Modified regular file file2.png: 2717 (binary) 2718 Added regular file file3.png: 2719 (binary) 2720 Added regular file file4.png: 2721 (binary) 2722 [EOF] 2723 "); 2724 2725 let output = work_dir.run_jj(["diff", "--git"]); 2726 insta::assert_snapshot!(output, @r" 2727 diff --git a/file1.png b/file1.png 2728 deleted file mode 100644 2729 index 2b65b23c22..0000000000 2730 Binary files a/file1.png and /dev/null differ 2731 diff --git a/file2.png b/file2.png 2732 index 7f036ce788..3bd1f0e297 100644 2733 Binary files a/file2.png and b/file2.png differ 2734 diff --git a/file3.png b/file3.png 2735 new file mode 100644 2736 index 0000000000..deacfbc286 2737 Binary files /dev/null and b/file3.png differ 2738 diff --git a/file4.png b/file4.png 2739 new file mode 100644 2740 index 0000000000..4227ca4e87 2741 Binary files /dev/null and b/file4.png differ 2742 [EOF] 2743 "); 2744 2745 let output = work_dir.run_jj(["diff", "--stat"]); 2746 insta::assert_snapshot!(output, @r" 2747 file1.png | 3 --- 2748 file2.png | 5 ++--- 2749 file3.png | 3 +++ 2750 file4.png | 1 + 2751 4 files changed, 6 insertions(+), 6 deletions(-) 2752 [EOF] 2753 "); 2754} 2755 2756#[test] 2757fn test_diff_revisions() { 2758 let test_env = TestEnvironment::default(); 2759 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2760 let work_dir = test_env.work_dir("repo"); 2761 2762 // 2763 // 2764 // 2765 // E 2766 // |\ 2767 // C D 2768 // |/ 2769 // B 2770 // | 2771 // A 2772 create_commit(&work_dir, "A", &[]); 2773 create_commit(&work_dir, "B", &["A"]); 2774 create_commit(&work_dir, "C", &["B"]); 2775 create_commit(&work_dir, "D", &["B"]); 2776 create_commit(&work_dir, "E", &["C", "D"]); 2777 2778 let diff_revisions = |expression: &str| -> CommandOutput { 2779 work_dir.run_jj(["diff", "--name-only", "-r", expression]) 2780 }; 2781 // Can diff a single revision 2782 insta::assert_snapshot!(diff_revisions("B"), @r" 2783 B 2784 [EOF] 2785 "); 2786 2787 // Can diff a merge 2788 insta::assert_snapshot!(diff_revisions("E"), @r" 2789 E 2790 [EOF] 2791 "); 2792 2793 // A gap in the range is not allowed (yet at least) 2794 insta::assert_snapshot!(diff_revisions("A|C"), @r" 2795 ------- stderr ------- 2796 Error: Cannot diff revsets with gaps in. 2797 Hint: Revision 50c75fd767bf would need to be in the set. 2798 [EOF] 2799 [exit status: 1] 2800 "); 2801 2802 // Can diff a linear chain 2803 insta::assert_snapshot!(diff_revisions("A::C"), @r" 2804 A 2805 B 2806 C 2807 [EOF] 2808 "); 2809 2810 // Can diff a chain with an internal merge 2811 insta::assert_snapshot!(diff_revisions("B::E"), @r" 2812 B 2813 C 2814 D 2815 E 2816 [EOF] 2817 "); 2818 2819 // Can diff a set with multiple roots 2820 insta::assert_snapshot!(diff_revisions("C|D|E"), @r" 2821 C 2822 D 2823 E 2824 [EOF] 2825 "); 2826 2827 // Can diff a set with multiple heads 2828 insta::assert_snapshot!(diff_revisions("B|C|D"), @r" 2829 B 2830 C 2831 D 2832 [EOF] 2833 "); 2834 2835 // Can diff a set with multiple root and multiple heads 2836 insta::assert_snapshot!(diff_revisions("B|C"), @r" 2837 B 2838 C 2839 [EOF] 2840 "); 2841}