just playing with tangled
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 std::path::Path;
16
17use crate::common::TestEnvironment;
18
19#[test]
20fn test_restore() {
21 let test_env = TestEnvironment::default();
22 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
23 let repo_path = test_env.env_root().join("repo");
24
25 std::fs::write(repo_path.join("file1"), "a\n").unwrap();
26 test_env.jj_cmd_ok(&repo_path, &["new"]);
27 std::fs::write(repo_path.join("file2"), "b\n").unwrap();
28 test_env.jj_cmd_ok(&repo_path, &["new"]);
29 std::fs::remove_file(repo_path.join("file1")).unwrap();
30 std::fs::write(repo_path.join("file2"), "c\n").unwrap();
31 std::fs::write(repo_path.join("file3"), "c\n").unwrap();
32
33 // There is no `-r` argument
34 let stderr = test_env.jj_cmd_failure(&repo_path, &["restore", "-r=@-"]);
35 insta::assert_snapshot!(stderr, @r###"
36 Error: `jj restore` does not have a `--revision`/`-r` option. If you'd like to modify
37 the *current* revision, use `--from`. If you'd like to modify a *different* revision,
38 use `--to` or `--changes-in`.
39 "###);
40
41 // Restores from parent by default
42 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["restore"]);
43 insta::assert_snapshot!(stdout, @"");
44 insta::assert_snapshot!(stderr, @r###"
45 Created kkmpptxz ed1678e3 (empty) (no description set)
46 Working copy now at: kkmpptxz ed1678e3 (empty) (no description set)
47 Parent commit : rlvkpnrz 1a986a27 (no description set)
48 Added 1 files, modified 1 files, removed 1 files
49 "###);
50 let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]);
51 insta::assert_snapshot!(stdout, @"");
52
53 // Can restore another revision from its parents
54 test_env.jj_cmd_ok(&repo_path, &["undo"]);
55 let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s", "-r=@-"]);
56 insta::assert_snapshot!(stdout, @r###"
57 A file2
58 "###);
59 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["restore", "-c=@-"]);
60 insta::assert_snapshot!(stdout, @"");
61 insta::assert_snapshot!(stderr, @r###"
62 Created rlvkpnrz e25100af (empty) (no description set)
63 Rebased 1 descendant commits
64 New conflicts appeared in these commits:
65 kkmpptxz 4906178a (conflict) (no description set)
66 To resolve the conflicts, start by updating to it:
67 jj new kkmpptxzrspx
68 Then use `jj resolve`, or edit the conflict markers in the file directly.
69 Once the conflicts are resolved, you may want inspect the result with `jj diff`.
70 Then run `jj squash` to move the resolution into the conflicted commit.
71 Working copy now at: kkmpptxz 4906178a (conflict) (no description set)
72 Parent commit : rlvkpnrz e25100af (empty) (no description set)
73 Added 0 files, modified 1 files, removed 0 files
74 There are unresolved conflicts at these paths:
75 file2 2-sided conflict including 1 deletion
76 "###);
77 let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s", "-r=@-"]);
78 insta::assert_snapshot!(stdout, @"");
79
80 // Can restore this revision from another revision
81 test_env.jj_cmd_ok(&repo_path, &["undo"]);
82 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["restore", "--from", "@--"]);
83 insta::assert_snapshot!(stdout, @"");
84 insta::assert_snapshot!(stderr, @r###"
85 Created kkmpptxz 1dd6eb63 (no description set)
86 Working copy now at: kkmpptxz 1dd6eb63 (no description set)
87 Parent commit : rlvkpnrz 1a986a27 (no description set)
88 Added 1 files, modified 0 files, removed 2 files
89 "###);
90 let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]);
91 insta::assert_snapshot!(stdout, @r###"
92 D file2
93 "###);
94
95 // Can restore into other revision
96 test_env.jj_cmd_ok(&repo_path, &["undo"]);
97 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["restore", "--to", "@-"]);
98 insta::assert_snapshot!(stdout, @"");
99 insta::assert_snapshot!(stderr, @r###"
100 Created rlvkpnrz ec9d5b59 (no description set)
101 Rebased 1 descendant commits
102 Working copy now at: kkmpptxz d6f3c681 (empty) (no description set)
103 Parent commit : rlvkpnrz ec9d5b59 (no description set)
104 "###);
105 let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]);
106 insta::assert_snapshot!(stdout, @"");
107 let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s", "-r", "@-"]);
108 insta::assert_snapshot!(stdout, @r###"
109 D file1
110 A file2
111 A file3
112 "###);
113
114 // Can combine `--from` and `--to`
115 test_env.jj_cmd_ok(&repo_path, &["undo"]);
116 let (stdout, stderr) =
117 test_env.jj_cmd_ok(&repo_path, &["restore", "--from", "@", "--to", "@-"]);
118 insta::assert_snapshot!(stdout, @"");
119 insta::assert_snapshot!(stderr, @r###"
120 Created rlvkpnrz 5f6eb3d5 (no description set)
121 Rebased 1 descendant commits
122 Working copy now at: kkmpptxz 525afd5d (empty) (no description set)
123 Parent commit : rlvkpnrz 5f6eb3d5 (no description set)
124 "###);
125 let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]);
126 insta::assert_snapshot!(stdout, @"");
127 let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s", "-r", "@-"]);
128 insta::assert_snapshot!(stdout, @r###"
129 D file1
130 A file2
131 A file3
132 "###);
133
134 // Can restore only specified paths
135 test_env.jj_cmd_ok(&repo_path, &["undo"]);
136 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["restore", "file2", "file3"]);
137 insta::assert_snapshot!(stdout, @"");
138 insta::assert_snapshot!(stderr, @r###"
139 Created kkmpptxz 569ce73d (no description set)
140 Working copy now at: kkmpptxz 569ce73d (no description set)
141 Parent commit : rlvkpnrz 1a986a27 (no description set)
142 Added 0 files, modified 1 files, removed 1 files
143 "###);
144 let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]);
145 insta::assert_snapshot!(stdout, @r###"
146 D file1
147 "###);
148}
149
150// Much of this test is copied from test_resolve_command
151#[test]
152fn test_restore_conflicted_merge() {
153 let test_env = TestEnvironment::default();
154 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
155 let repo_path = test_env.env_root().join("repo");
156
157 create_commit(&test_env, &repo_path, "base", &[], &[("file", "base\n")]);
158 create_commit(&test_env, &repo_path, "a", &["base"], &[("file", "a\n")]);
159 create_commit(&test_env, &repo_path, "b", &["base"], &[("file", "b\n")]);
160 create_commit(&test_env, &repo_path, "conflict", &["a", "b"], &[]);
161 // Test the setup
162 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
163 @ conflict
164 ├─╮
165 │ ◉ b
166 ◉ │ a
167 ├─╯
168 ◉ base
169 ◉
170 "###);
171 insta::assert_snapshot!(
172 std::fs::read_to_string(repo_path.join("file")).unwrap()
173 , @r###"
174 <<<<<<< Conflict 1 of 1
175 %%%%%%% Changes from base to side #1
176 -base
177 +a
178 +++++++ Contents of side #2
179 b
180 >>>>>>>
181 "###);
182
183 // Overwrite the file...
184 std::fs::write(repo_path.join("file"), "resolution").unwrap();
185 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff"]),
186 @r###"
187 Resolved conflict in file:
188 1 : <<<<<<< Conflict 1 of 1
189 2 : %%%%%%% Changes from base to side #1
190 3 : -base
191 4 : +a
192 5 : +++++++ Contents of side #2
193 6 : b
194 7 : >>>>>>>
195 1: resolution
196 "###);
197
198 // ...and restore it back again.
199 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["restore", "file"]);
200 insta::assert_snapshot!(stdout, @"");
201 insta::assert_snapshot!(stderr, @r###"
202 Created vruxwmqv 126facb5 conflict | (conflict) (empty) conflict
203 Working copy now at: vruxwmqv 126facb5 conflict | (conflict) (empty) conflict
204 Parent commit : zsuskuln aa493daf a | a
205 Parent commit : royxmykx db6a4daf b | b
206 Added 0 files, modified 1 files, removed 0 files
207 There are unresolved conflicts at these paths:
208 file 2-sided conflict
209 "###);
210 insta::assert_snapshot!(
211 std::fs::read_to_string(repo_path.join("file")).unwrap()
212 , @r###"
213 <<<<<<< Conflict 1 of 1
214 %%%%%%% Changes from base to side #1
215 -base
216 +a
217 +++++++ Contents of side #2
218 b
219 >>>>>>>
220 "###);
221 let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);
222 insta::assert_snapshot!(stdout, @"");
223
224 // The same, but without the `file` argument. Overwrite the file...
225 std::fs::write(repo_path.join("file"), "resolution").unwrap();
226 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff"]),
227 @r###"
228 Resolved conflict in file:
229 1 : <<<<<<< Conflict 1 of 1
230 2 : %%%%%%% Changes from base to side #1
231 3 : -base
232 4 : +a
233 5 : +++++++ Contents of side #2
234 6 : b
235 7 : >>>>>>>
236 1: resolution
237 "###);
238
239 // ... and restore it back again.
240 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["restore"]);
241 insta::assert_snapshot!(stdout, @"");
242 insta::assert_snapshot!(stderr, @r###"
243 Created vruxwmqv b553ebcf conflict | (conflict) (empty) conflict
244 Working copy now at: vruxwmqv b553ebcf conflict | (conflict) (empty) conflict
245 Parent commit : zsuskuln aa493daf a | a
246 Parent commit : royxmykx db6a4daf b | b
247 Added 0 files, modified 1 files, removed 0 files
248 There are unresolved conflicts at these paths:
249 file 2-sided conflict
250 "###);
251 insta::assert_snapshot!(
252 std::fs::read_to_string(repo_path.join("file")).unwrap()
253 , @r###"
254 <<<<<<< Conflict 1 of 1
255 %%%%%%% Changes from base to side #1
256 -base
257 +a
258 +++++++ Contents of side #2
259 b
260 >>>>>>>
261 "###);
262}
263
264fn create_commit(
265 test_env: &TestEnvironment,
266 repo_path: &Path,
267 name: &str,
268 parents: &[&str],
269 files: &[(&str, &str)],
270) {
271 if parents.is_empty() {
272 test_env.jj_cmd_ok(repo_path, &["new", "root()", "-m", name]);
273 } else {
274 let mut args = vec!["new", "-m", name];
275 args.extend(parents);
276 test_env.jj_cmd_ok(repo_path, &args);
277 }
278 for (name, content) in files {
279 std::fs::write(repo_path.join(name), content).unwrap();
280 }
281 test_env.jj_cmd_ok(repo_path, &["branch", "create", name]);
282}
283
284fn get_log_output(test_env: &TestEnvironment, repo_path: &Path) -> String {
285 test_env.jj_cmd_success(repo_path, &["log", "-T", "branches"])
286}