just playing with tangled
1// Copyright 2020 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 jj_lib::backend::{ChangeId, MillisSinceEpoch, ObjectId, Signature, Timestamp};
16use jj_lib::matchers::EverythingMatcher;
17use jj_lib::repo::Repo;
18use jj_lib::repo_path::RepoPath;
19use jj_lib::settings::UserSettings;
20use jj_lib::tree::DiffSummary;
21use test_case::test_case;
22use testutils::{assert_rebased, CommitGraphBuilder, TestRepo};
23
24#[test_case(false ; "local backend")]
25#[test_case(true ; "git backend")]
26fn test_initial(use_git: bool) {
27 let settings = testutils::user_settings();
28 let test_repo = TestRepo::init(use_git);
29 let repo = &test_repo.repo;
30 let store = repo.store();
31
32 let root_file_path = RepoPath::from_internal_string("file");
33 let dir_file_path = RepoPath::from_internal_string("dir/file");
34 let tree = testutils::create_tree(
35 repo,
36 &[
37 (&root_file_path, "file contents"),
38 (&dir_file_path, "dir/file contents"),
39 ],
40 );
41
42 let mut tx = repo.start_transaction(&settings, "test");
43 let author_signature = Signature {
44 name: "author name".to_string(),
45 email: "author email".to_string(),
46 timestamp: Timestamp {
47 timestamp: MillisSinceEpoch(1000),
48 tz_offset: 60,
49 },
50 };
51 let committer_signature = Signature {
52 name: "committer name".to_string(),
53 email: "committer email".to_string(),
54 timestamp: Timestamp {
55 timestamp: MillisSinceEpoch(2000),
56 tz_offset: -60,
57 },
58 };
59 let change_id = ChangeId::new(vec![100u8; 16]);
60 let builder = tx
61 .mut_repo()
62 .new_commit(
63 &settings,
64 vec![store.root_commit_id().clone()],
65 tree.id().clone(),
66 )
67 .set_change_id(change_id.clone())
68 .set_description("description")
69 .set_author(author_signature.clone())
70 .set_committer(committer_signature.clone());
71 assert_eq!(builder.parents(), &[store.root_commit_id().clone()]);
72 assert_eq!(builder.predecessors(), &[]);
73 assert_eq!(builder.tree(), tree.id());
74 assert_eq!(builder.change_id(), &change_id);
75 assert_eq!(builder.author(), &author_signature);
76 assert_eq!(builder.committer(), &committer_signature);
77 let commit = builder.write().unwrap();
78 tx.commit();
79
80 assert_eq!(commit.parents(), vec![store.root_commit()]);
81 assert_eq!(commit.predecessors(), vec![]);
82 assert_eq!(commit.description(), "description");
83 assert_eq!(commit.author(), &author_signature);
84 assert_eq!(commit.committer(), &committer_signature);
85 assert_eq!(
86 store
87 .root_commit()
88 .tree()
89 .diff_summary(&commit.tree(), &EverythingMatcher),
90 DiffSummary {
91 modified: vec![],
92 added: vec![dir_file_path, root_file_path],
93 removed: vec![]
94 }
95 );
96}
97
98#[test_case(false ; "local backend")]
99#[test_case(true ; "git backend")]
100fn test_rewrite(use_git: bool) {
101 let settings = testutils::user_settings();
102 let test_repo = TestRepo::init(use_git);
103 let repo = &test_repo.repo;
104 let store = repo.store().clone();
105
106 let root_file_path = RepoPath::from_internal_string("file");
107 let dir_file_path = RepoPath::from_internal_string("dir/file");
108 let initial_tree = testutils::create_tree(
109 repo,
110 &[
111 (&root_file_path, "file contents"),
112 (&dir_file_path, "dir/file contents"),
113 ],
114 );
115
116 let mut tx = repo.start_transaction(&settings, "test");
117 let initial_commit = tx
118 .mut_repo()
119 .new_commit(
120 &settings,
121 vec![store.root_commit_id().clone()],
122 initial_tree.id().clone(),
123 )
124 .write()
125 .unwrap();
126 let repo = tx.commit();
127
128 let rewritten_tree = testutils::create_tree(
129 &repo,
130 &[
131 (&root_file_path, "file contents"),
132 (&dir_file_path, "updated dir/file contents"),
133 ],
134 );
135
136 let config = config::Config::builder()
137 .set_override("user.name", "Rewrite User")
138 .unwrap()
139 .set_override("user.email", "rewrite.user@example.com")
140 .unwrap()
141 .build()
142 .unwrap();
143 let rewrite_settings = UserSettings::from_config(config);
144 let mut tx = repo.start_transaction(&settings, "test");
145 let rewritten_commit = tx
146 .mut_repo()
147 .rewrite_commit(&rewrite_settings, &initial_commit)
148 .set_tree(rewritten_tree.id().clone())
149 .write()
150 .unwrap();
151 tx.mut_repo().rebase_descendants(&settings).unwrap();
152 tx.commit();
153 assert_eq!(rewritten_commit.parents(), vec![store.root_commit()]);
154 assert_eq!(
155 rewritten_commit.predecessors(),
156 vec![initial_commit.clone()]
157 );
158 assert_eq!(rewritten_commit.author().name, settings.user_name());
159 assert_eq!(rewritten_commit.author().email, settings.user_email());
160 assert_eq!(
161 rewritten_commit.committer().name,
162 rewrite_settings.user_name()
163 );
164 assert_eq!(
165 rewritten_commit.committer().email,
166 rewrite_settings.user_email()
167 );
168 assert_eq!(
169 store
170 .root_commit()
171 .tree()
172 .diff_summary(&rewritten_commit.tree(), &EverythingMatcher),
173 DiffSummary {
174 modified: vec![],
175 added: vec![dir_file_path.clone(), root_file_path],
176 removed: vec![]
177 }
178 );
179 assert_eq!(
180 initial_commit
181 .tree()
182 .diff_summary(&rewritten_commit.tree(), &EverythingMatcher),
183 DiffSummary {
184 modified: vec![dir_file_path],
185 added: vec![],
186 removed: vec![]
187 }
188 );
189}
190
191// An author field with the placeholder name/email should get filled in on
192// rewrite
193#[test_case(false ; "local backend")]
194#[test_case(true ; "git backend")]
195fn test_rewrite_update_missing_user(use_git: bool) {
196 let missing_user_settings =
197 UserSettings::from_config(config::Config::builder().build().unwrap());
198 let test_repo = TestRepo::init(use_git);
199 let repo = &test_repo.repo;
200
201 let mut tx = repo.start_transaction(&missing_user_settings, "test");
202 let initial_commit = tx
203 .mut_repo()
204 .new_commit(
205 &missing_user_settings,
206 vec![repo.store().root_commit_id().clone()],
207 repo.store().empty_tree_id().clone(),
208 )
209 .write()
210 .unwrap();
211 assert_eq!(initial_commit.author().name, "(no name configured)");
212 assert_eq!(initial_commit.author().email, "(no email configured)");
213 assert_eq!(initial_commit.committer().name, "(no name configured)");
214 assert_eq!(initial_commit.committer().email, "(no email configured)");
215
216 let config = config::Config::builder()
217 .set_override("user.name", "Configured User")
218 .unwrap()
219 .set_override("user.email", "configured.user@example.com")
220 .unwrap()
221 .build()
222 .unwrap();
223 let settings = UserSettings::from_config(config);
224 let rewritten_commit = tx
225 .mut_repo()
226 .rewrite_commit(&settings, &initial_commit)
227 .write()
228 .unwrap();
229
230 assert_eq!(rewritten_commit.author().name, "Configured User");
231 assert_eq!(
232 rewritten_commit.author().email,
233 "configured.user@example.com"
234 );
235 assert_eq!(rewritten_commit.committer().name, "Configured User");
236 assert_eq!(
237 rewritten_commit.committer().email,
238 "configured.user@example.com"
239 );
240}
241
242#[test_case(false ; "local backend")]
243// #[test_case(true ; "git backend")]
244fn test_commit_builder_descendants(use_git: bool) {
245 let settings = testutils::user_settings();
246 let test_repo = TestRepo::init(use_git);
247 let repo = &test_repo.repo;
248 let store = repo.store().clone();
249
250 let mut tx = repo.start_transaction(&settings, "test");
251 let mut graph_builder = CommitGraphBuilder::new(&settings, tx.mut_repo());
252 let commit1 = graph_builder.initial_commit();
253 let commit2 = graph_builder.commit_with_parents(&[&commit1]);
254 let commit3 = graph_builder.commit_with_parents(&[&commit2]);
255 let repo = tx.commit();
256
257 // Test with for_new_commit()
258 let mut tx = repo.start_transaction(&settings, "test");
259 tx.mut_repo()
260 .new_commit(
261 &settings,
262 vec![store.root_commit_id().clone()],
263 store.empty_tree_id().clone(),
264 )
265 .write()
266 .unwrap();
267 let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings);
268 assert!(rebaser.rebase_next().unwrap().is_none());
269
270 // Test with for_rewrite_from()
271 let mut tx = repo.start_transaction(&settings, "test");
272 let commit4 = tx
273 .mut_repo()
274 .rewrite_commit(&settings, &commit2)
275 .write()
276 .unwrap();
277 let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings);
278 assert_rebased(rebaser.rebase_next().unwrap(), &commit3, &[&commit4]);
279 assert!(rebaser.rebase_next().unwrap().is_none());
280
281 // Test with for_rewrite_from() but new change id
282 let mut tx = repo.start_transaction(&settings, "test");
283 tx.mut_repo()
284 .rewrite_commit(&settings, &commit2)
285 .generate_new_change_id()
286 .write()
287 .unwrap();
288 let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings);
289 assert!(rebaser.rebase_next().unwrap().is_none());
290}