jj/cli/tests/test_next_prev_commands.rs
Scott Taylor 1eebbe57c0 commit_builder: reset author timestamp on discardable commits
It's common to create empty working-copy commits while using jj, and
currently the author timestamp for a commit is only set when it is first
created. If you create an empty commit, then don't work on a repo for a
few days, and then start working on a new feature without abandoning the
working-copy commit, the author timestamp will remain as the time the
commit was created rather than being updated to the time that work began
or finished.

This commit changes the behavior so that discardable commits (empty
commits with no description) by the current user have their author
timestamps reset when they are rewritten, meaning that the author
timestamp will become finalized whenever a commit is given a description
or becomes non-empty.
2024-06-29 08:35:53 -05:00

739 lines
28 KiB
Rust

// Copyright 2023 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
use std::path::Path;
use crate::common::{get_stderr_string, get_stdout_string, TestEnvironment};
#[test]
fn test_next_simple() {
// Move from first => second.
// first
// |
// second
// |
// third
//
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
// Create a simple linear history, which we'll traverse.
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
// Move to `first`
test_env.jj_cmd_ok(&repo_path, &["new", "@--"]);
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["next"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Working copy now at: royxmykx fb00d619 (empty) (no description set)
Parent commit : kkmpptxz 30056b0c (empty) third
"###);
}
#[test]
fn test_next_multiple() {
// Move from first => fourth.
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "fourth"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@---"]);
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["next", "2"]);
// We should now be the child of the fourth commit.
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Working copy now at: yqosqzyt 50168682 (empty) (no description set)
Parent commit : zsuskuln 9d7e5e99 (empty) fourth
"###);
}
#[test]
fn test_prev_simple() {
// Move @- from third to second.
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ zsuskulnrvyr
◉ kkmpptxzrspx third
◉ rlvkpnrzqnoo second
◉ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["prev"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Working copy now at: royxmykx 6db74f64 (empty) (no description set)
Parent commit : rlvkpnrz 9ed53a4a (empty) second
"###);
}
#[test]
fn test_prev_multiple_without_root() {
// Move @- from fourth to second.
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "fourth"]);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ mzvwutvlkqwt
◉ zsuskulnrvyr fourth
◉ kkmpptxzrspx third
◉ rlvkpnrzqnoo second
◉ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["prev", "2"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Working copy now at: yqosqzyt 794ffd20 (empty) (no description set)
Parent commit : rlvkpnrz 9ed53a4a (empty) second
"###);
}
#[test]
fn test_next_exceeding_history() {
// Try to step beyond the current repos history.
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
test_env.jj_cmd_ok(&repo_path, &["edit", "-r", "@--"]);
let stderr = test_env.jj_cmd_failure(&repo_path, &["next", "3"]);
// `jj next` beyond existing history fails.
insta::assert_snapshot!(stderr, @r###"
Error: No descendant found 3 commits forward
"###);
}
// The working copy commit is a child of a "fork" with two children on each
// branch.
#[test]
fn test_next_parent_has_multiple_descendants() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
// Setup.
test_env.jj_cmd_ok(&repo_path, &["desc", "-m", "1"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-m", "2"]);
test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m", "3"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-m", "4"]);
test_env.jj_cmd_ok(&repo_path, &["edit", "description(3)"]);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
◉ mzvwutvlkqwt 4
@ zsuskulnrvyr 3
│ ◉ kkmpptxzrspx 2
│ ◉ qpvuntsmwlqt 1
├─╯
◉ zzzzzzzzzzzz
"###);
// --edit is implied since the working copy isn't a leaf commit.
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["next"]);
insta::assert_snapshot!(stdout,@r###""###);
insta::assert_snapshot!(stderr,@r###"
Working copy now at: mzvwutvl 1b8531ce (empty) 4
Parent commit : zsuskuln b1394455 (empty) 3
"###);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ mzvwutvlkqwt 4
◉ zsuskulnrvyr 3
│ ◉ kkmpptxzrspx 2
│ ◉ qpvuntsmwlqt 1
├─╯
◉ zzzzzzzzzzzz
"###);
}
#[test]
fn test_next_with_merge_commit_parent() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
// Setup.
test_env.jj_cmd_ok(&repo_path, &["desc", "-m", "1"]);
test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m", "2"]);
test_env.jj_cmd_ok(
&repo_path,
&["new", "description(1)", "description(2)", "-m", "3"],
);
test_env.jj_cmd_ok(&repo_path, &["new", "-m", "4"]);
test_env.jj_cmd_ok(&repo_path, &["prev", "0"]);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ royxmykxtrkr
│ ◉ mzvwutvlkqwt 4
├─╯
◉ zsuskulnrvyr 3
├─╮
│ ◉ kkmpptxzrspx 2
◉ │ qpvuntsmwlqt 1
├─╯
◉ zzzzzzzzzzzz
"###);
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["next"]);
insta::assert_snapshot!(stdout,@r###""###);
insta::assert_snapshot!(stderr,@r###"
Working copy now at: vruxwmqv e2cefcb7 (empty) (no description set)
Parent commit : mzvwutvl b54bbdea (empty) 4
"###);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ vruxwmqvtpmx
◉ mzvwutvlkqwt 4
◉ zsuskulnrvyr 3
├─╮
│ ◉ kkmpptxzrspx 2
◉ │ qpvuntsmwlqt 1
├─╯
◉ zzzzzzzzzzzz
"###);
}
#[test]
fn test_next_on_merge_commit() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
// Setup.
test_env.jj_cmd_ok(&repo_path, &["desc", "-m", "1"]);
test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m", "2"]);
test_env.jj_cmd_ok(
&repo_path,
&["new", "description(1)", "description(2)", "-m", "3"],
);
test_env.jj_cmd_ok(&repo_path, &["new", "-m", "4"]);
test_env.jj_cmd_ok(&repo_path, &["edit", "description(3)"]);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
◉ mzvwutvlkqwt 4
@ zsuskulnrvyr 3
├─╮
│ ◉ kkmpptxzrspx 2
◉ │ qpvuntsmwlqt 1
├─╯
◉ zzzzzzzzzzzz
"###);
// --edit is implied since the working copy is not a leaf commit.
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["next"]);
insta::assert_snapshot!(stdout,@r###""###);
insta::assert_snapshot!(stderr,@r###"
Working copy now at: mzvwutvl b54bbdea (empty) 4
Parent commit : zsuskuln 5542f0b4 (empty) 3
"###);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ mzvwutvlkqwt 4
◉ zsuskulnrvyr 3
├─╮
│ ◉ kkmpptxzrspx 2
◉ │ qpvuntsmwlqt 1
├─╯
◉ zzzzzzzzzzzz
"###);
}
#[test]
fn test_next_fails_on_branching_children_no_stdin() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@--"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@--"]);
// Try to advance the working copy commit.
let assert = test_env.jj_cmd(&repo_path, &["next"]).assert().code(1);
let stderr = test_env.normalize_output(&get_stderr_string(&assert));
insta::assert_snapshot!(stderr,@r###"
Error: Cannot prompt for input since the output is not connected to a terminal
"###);
}
#[test]
fn test_next_fails_on_branching_children_quit_prompt() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@--"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@--"]);
// Try to advance the working copy commit.
let assert = test_env
.jj_cmd_stdin(&repo_path, &["next"], "q\n")
.assert()
.code(1);
let stdout = test_env.normalize_output(&get_stdout_string(&assert));
let stderr = test_env.normalize_output(&get_stderr_string(&assert));
insta::assert_snapshot!(stdout,@r###"
ambiguous next commit, choose one to target:
1: zsuskuln 5f24490d (empty) third
2: rlvkpnrz 9ed53a4a (empty) second
q: quit the prompt
enter the index of the commit you want to target:
"###);
insta::assert_snapshot!(stderr,@r###"
Error: ambiguous target commit
"###);
}
#[test]
fn test_next_choose_branching_child() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@--"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@--"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "fourth"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@--"]);
// Advance the working copy commit.
let (stdout, stderr) = test_env.jj_cmd_stdin_ok(&repo_path, &["next"], "2\n");
insta::assert_snapshot!(stdout,@r###"
ambiguous next commit, choose one to target:
1: royxmykx d00fe885 (empty) fourth
2: zsuskuln 5f24490d (empty) third
3: rlvkpnrz 9ed53a4a (empty) second
q: quit the prompt
enter the index of the commit you want to target:
"###);
insta::assert_snapshot!(stderr,@r###"
Working copy now at: yostqsxw 5c8fa96d (empty) (no description set)
Parent commit : zsuskuln 5f24490d (empty) third
"###);
}
#[test]
fn test_prev_on_merge_commit() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["desc", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["branch", "c", "left"]);
test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["branch", "c", "right"]);
test_env.jj_cmd_ok(&repo_path, &["new", "left", "right"]);
// Check that the graph looks the way we expect.
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ royxmykxtrkr
├─╮
│ ◉ zsuskulnrvyr right second
◉ │ qpvuntsmwlqt left first
├─╯
◉ zzzzzzzzzzzz
"###);
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["prev"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr,@r###"
Working copy now at: vruxwmqv 41658cf4 (empty) (no description set)
Parent commit : zzzzzzzz 00000000 (empty) (no description set)
"###);
test_env.jj_cmd_ok(&repo_path, &["undo"]);
let (stdout, stderr) = test_env.jj_cmd_stdin_ok(&repo_path, &["prev", "--edit"], "2\n");
insta::assert_snapshot!(stdout, @r###"
ambiguous prev commit, choose one to target:
1: zsuskuln b0d21db3 right | (empty) second
2: qpvuntsm fa15625b left | (empty) first
q: quit the prompt
enter the index of the commit you want to target:
"###);
insta::assert_snapshot!(stderr,@r###"
Working copy now at: qpvuntsm fa15625b left | (empty) first
Parent commit : zzzzzzzz 00000000 (empty) (no description set)
"###);
}
#[test]
fn test_prev_on_merge_commit_with_parent_merge() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["desc", "-m", "x"]);
test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m", "y"]);
test_env.jj_cmd_ok(
&repo_path,
&["new", "description(x)", "description(y)", "-m", "z"],
);
test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m", "1"]);
test_env.jj_cmd_ok(
&repo_path,
&["new", "description(z)", "description(1)", "-m", "M"],
);
// Check that the graph looks the way we expect.
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ royxmykxtrkr M
├─╮
│ ◉ mzvwutvlkqwt 1
◉ │ zsuskulnrvyr z
├───╮
│ │ ◉ kkmpptxzrspx y
│ ├─╯
◉ │ qpvuntsmwlqt x
├─╯
◉ zzzzzzzzzzzz
"###);
let (stdout, stderr) = test_env.jj_cmd_stdin_ok(&repo_path, &["prev"], "2\n");
insta::assert_snapshot!(stdout, @r###"
ambiguous prev commit, choose one to target:
1: kkmpptxz 146d5c67 (empty) y
2: qpvuntsm 6799aaa2 (empty) x
3: zzzzzzzz 00000000 (empty) (no description set)
q: quit the prompt
enter the index of the commit you want to target:
"###);
insta::assert_snapshot!(stderr,@r###"
Working copy now at: vruxwmqv e5a6794c (empty) (no description set)
Parent commit : qpvuntsm 6799aaa2 (empty) x
"###);
test_env.jj_cmd_ok(&repo_path, &["undo"]);
let (stdout, stderr) = test_env.jj_cmd_stdin_ok(&repo_path, &["prev", "--edit"], "2\n");
insta::assert_snapshot!(stdout, @r###"
ambiguous prev commit, choose one to target:
1: mzvwutvl 89b8a355 (empty) 1
2: zsuskuln a83fc061 (empty) z
q: quit the prompt
enter the index of the commit you want to target:
"###);
insta::assert_snapshot!(stderr,@r###"
Working copy now at: zsuskuln a83fc061 (empty) z
Parent commit : qpvuntsm 6799aaa2 (empty) x
Parent commit : kkmpptxz 146d5c67 (empty) y
"###);
}
#[test]
fn test_prev_prompts_on_multiple_parents() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@--"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@--"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
// Create a merge commit, which has two parents.
test_env.jj_cmd_ok(&repo_path, &["new", "all:@--+"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "merge"]);
// Check that the graph looks the way we expect.
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ vruxwmqvtpmx
◉ yqosqzytrlsw merge
├─┬─╮
│ │ ◉ qpvuntsmwlqt first
│ ◉ │ kkmpptxzrspx second
│ ├─╯
◉ │ mzvwutvlkqwt third
├─╯
◉ zzzzzzzzzzzz
"###);
// Move @ backwards.
let (stdout, stderr) = test_env.jj_cmd_stdin_ok(&repo_path, &["prev"], "3\n");
insta::assert_snapshot!(stdout,@r###"
ambiguous prev commit, choose one to target:
1: mzvwutvl bc4f4fe3 (empty) third
2: kkmpptxz b0d21db3 (empty) second
3: qpvuntsm fa15625b (empty) first
q: quit the prompt
enter the index of the commit you want to target:
"###);
insta::assert_snapshot!(stderr,@r###"
Working copy now at: znkkpsqq 07b409e8 (empty) (no description set)
Parent commit : qpvuntsm fa15625b (empty) first
"###);
}
#[test]
fn test_prev_beyond_root_fails() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "fourth"]);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ mzvwutvlkqwt
◉ zsuskulnrvyr fourth
◉ kkmpptxzrspx third
◉ rlvkpnrzqnoo second
◉ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
// @- is at "fourth", and there is no parent 5 commits behind it.
let stderr = test_env.jj_cmd_failure(&repo_path, &["prev", "5"]);
insta::assert_snapshot!(stderr,@r###"
Error: No ancestor found 5 commits back
"###);
}
#[test]
fn test_prev_editing() {
// Edit the third commit.
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "fourth"]);
// Edit the "fourth" commit, which becomes the leaf.
test_env.jj_cmd_ok(&repo_path, &["edit", "@-"]);
// Check that the graph looks the way we expect.
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ zsuskulnrvyr fourth
◉ kkmpptxzrspx third
◉ rlvkpnrzqnoo second
◉ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["prev", "--edit"]);
insta::assert_snapshot!(stdout, @r"");
insta::assert_snapshot!(stderr, @r###"
Working copy now at: kkmpptxz 30056b0c (empty) third
Parent commit : rlvkpnrz 9ed53a4a (empty) second
"###);
// --edit is implied when already editing a non-head commit
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["prev"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Working copy now at: rlvkpnrz 9ed53a4a (empty) second
Parent commit : qpvuntsm fa15625b (empty) first
"###);
}
#[test]
fn test_next_editing() {
// Edit the second commit.
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "fourth"]);
test_env.jj_cmd_ok(&repo_path, &["edit", "@---"]);
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["next", "--edit"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Working copy now at: kkmpptxz 30056b0c (empty) third
Parent commit : rlvkpnrz 9ed53a4a (empty) second
"###);
// --edit is implied when already editing a non-head commit
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["next"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Working copy now at: zsuskuln 9d7e5e99 (empty) fourth
Parent commit : kkmpptxz 30056b0c (empty) third
"###);
}
#[test]
fn test_prev_conflict() {
// Make the first commit our new parent.
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
let file_path = repo_path.join("content.txt");
std::fs::write(&file_path, "first").unwrap();
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
std::fs::write(&file_path, "second").unwrap();
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
// Create a conflict in the first commit, where we'll jump to.
test_env.jj_cmd_ok(&repo_path, &["edit", "description(first)"]);
std::fs::write(&file_path, "first+1").unwrap();
test_env.jj_cmd_ok(&repo_path, &["new", "description(third)"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "fourth"]);
// Test the setup
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ yqosqzytrlsw conflict
◉ royxmykxtrkr conflict fourth
◉ kkmpptxzrspx conflict third
◉ rlvkpnrzqnoo conflict second
◉ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
test_env.jj_cmd_ok(&repo_path, &["prev", "--conflict"]);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ yostqsxwqrlt conflict
│ ◉ royxmykxtrkr conflict fourth
├─╯
◉ kkmpptxzrspx conflict third
◉ rlvkpnrzqnoo conflict second
◉ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
}
#[test]
fn test_prev_conflict_editing() {
// Edit the third commit.
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
let file_path = repo_path.join("content.txt");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
std::fs::write(&file_path, "second").unwrap();
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
// Create a conflict in the third commit, where we'll jump to.
test_env.jj_cmd_ok(&repo_path, &["edit", "description(first)"]);
std::fs::write(&file_path, "first text").unwrap();
test_env.jj_cmd_ok(&repo_path, &["new", "description(third)"]);
// Test the setup
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ royxmykxtrkr conflict
◉ kkmpptxzrspx conflict third
◉ rlvkpnrzqnoo second
◉ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
test_env.jj_cmd_ok(&repo_path, &["prev", "--conflict", "--edit"]);
// We now should be editing the third commit.
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ kkmpptxzrspx conflict third
◉ rlvkpnrzqnoo second
◉ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
}
#[test]
fn test_next_conflict() {
// There is a conflict in the third commit, so after next it should be the new
// parent.
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
let file_path = repo_path.join("content.txt");
std::fs::write(&file_path, "first").unwrap();
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
// Create a conflict in the third commit.
std::fs::write(&file_path, "third").unwrap();
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "third"]);
test_env.jj_cmd_ok(&repo_path, &["new", "description(first)"]);
std::fs::write(&file_path, "first v2").unwrap();
test_env.jj_cmd_ok(&repo_path, &["squash", "--into", "description(third)"]);
// Test the setup
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ royxmykxtrkr
│ ◉ kkmpptxzrspx conflict third
│ ◉ rlvkpnrzqnoo second
├─╯
◉ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
test_env.jj_cmd_ok(&repo_path, &["next", "--conflict"]);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ vruxwmqvtpmx conflict
◉ kkmpptxzrspx conflict third
◉ rlvkpnrzqnoo second
◉ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
}
#[test]
fn test_next_conflict_editing() {
// There is a conflict in the third commit, so after next it should be our
// working copy.
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
let file_path = repo_path.join("content.txt");
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "first"]);
std::fs::write(&file_path, "second").unwrap();
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "second"]);
// Create a conflict in the third commit.
std::fs::write(&file_path, "third").unwrap();
test_env.jj_cmd_ok(&repo_path, &["edit", "description(second)"]);
std::fs::write(&file_path, "modified second").unwrap();
test_env.jj_cmd_ok(&repo_path, &["edit", "@-"]);
// Test the setup
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
◉ kkmpptxzrspx conflict
◉ rlvkpnrzqnoo second
@ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
test_env.jj_cmd_ok(&repo_path, &["next", "--conflict", "--edit"]);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ kkmpptxzrspx conflict
◉ rlvkpnrzqnoo second
◉ qpvuntsmwlqt first
◉ zzzzzzzzzzzz
"###);
}
#[test]
fn test_next_conflict_head() {
// When editing a head with conflicts, `jj next --conflict [--edit]` errors out.
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
let file_path = repo_path.join("file");
std::fs::write(&file_path, "first").unwrap();
test_env.jj_cmd_ok(&repo_path, &["new"]);
std::fs::write(&file_path, "second").unwrap();
test_env.jj_cmd_ok(&repo_path, &["abandon", "@-"]);
// Test the setup
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ rlvkpnrzqnoo conflict
◉ zzzzzzzzzzzz
"###);
let stderr = test_env.jj_cmd_failure(&repo_path, &["next", "--conflict"]);
insta::assert_snapshot!(stderr, @r###"
Error: No descendant found 1 commit forward
"###);
let stderr = test_env.jj_cmd_failure(&repo_path, &["next", "--conflict", "--edit"]);
insta::assert_snapshot!(stderr, @r###"
Error: No descendant found 1 commit forward
"###);
}
fn get_log_output(test_env: &TestEnvironment, cwd: &Path) -> String {
let template = r#"separate(" ", change_id.short(), local_branches, if(conflict, "conflict"), description)"#;
test_env.jj_cmd_success(cwd, &["log", "-T", template])
}