just playing with tangled
at diffedit3 244 lines 10 kB view raw
1// Copyright 2023 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 19fn create_commit( 20 test_env: &TestEnvironment, 21 repo_path: &Path, 22 name: &str, 23 parents: &[&str], 24 files: &[(&str, &str)], 25) { 26 if parents.is_empty() { 27 test_env.jj_cmd_ok(repo_path, &["new", "root()", "-m", name]); 28 } else { 29 let mut args = vec!["new", "-m", name]; 30 args.extend(parents); 31 test_env.jj_cmd_ok(repo_path, &args); 32 } 33 for (name, content) in files { 34 std::fs::write(repo_path.join(name), content).unwrap(); 35 } 36 test_env.jj_cmd_ok(repo_path, &["branch", "create", name]); 37} 38 39fn get_log_output(test_env: &TestEnvironment, repo_path: &Path) -> String { 40 test_env.jj_cmd_success(repo_path, &["log", "-T", "branches"]) 41} 42 43#[test] 44fn test_chmod_regular_conflict() { 45 let test_env = TestEnvironment::default(); 46 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 47 let repo_path = test_env.env_root().join("repo"); 48 49 create_commit(&test_env, &repo_path, "base", &[], &[("file", "base\n")]); 50 create_commit(&test_env, &repo_path, "n", &["base"], &[("file", "n\n")]); 51 create_commit(&test_env, &repo_path, "x", &["base"], &[("file", "x\n")]); 52 // Test chmodding a file. The effect will be visible in the conflict below. 53 test_env.jj_cmd_ok(&repo_path, &["chmod", "x", "file", "-r=x"]); 54 create_commit(&test_env, &repo_path, "conflict", &["x", "n"], &[]); 55 56 // Test the setup 57 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 58 @ conflict 59 ├─╮ 60 │ ◉ n 61 ◉ │ x 62 ├─╯ 63 ◉ base 64 65 "###); 66 let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree"]); 67 insta::assert_snapshot!(stdout, 68 @r###" 69 file: Ok(Conflicted([Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: true }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: false })])) 70 "###); 71 let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "file"]); 72 insta::assert_snapshot!(stdout, 73 @r###" 74 <<<<<<< Conflict 1 of 1 75 %%%%%%% Changes from base to side #1 76 -base 77 +x 78 +++++++ Contents of side #2 79 n 80 >>>>>>> 81 "###); 82 83 // Test chmodding a conflict 84 test_env.jj_cmd_ok(&repo_path, &["chmod", "x", "file"]); 85 let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree"]); 86 insta::assert_snapshot!(stdout, 87 @r###" 88 file: Ok(Conflicted([Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: true }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: true }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: true })])) 89 "###); 90 let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "file"]); 91 insta::assert_snapshot!(stdout, 92 @r###" 93 <<<<<<< Conflict 1 of 1 94 %%%%%%% Changes from base to side #1 95 -base 96 +x 97 +++++++ Contents of side #2 98 n 99 >>>>>>> 100 "###); 101 test_env.jj_cmd_ok(&repo_path, &["chmod", "n", "file"]); 102 let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree"]); 103 insta::assert_snapshot!(stdout, 104 @r###" 105 file: Ok(Conflicted([Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: false })])) 106 "###); 107 let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "file"]); 108 insta::assert_snapshot!(stdout, 109 @r###" 110 <<<<<<< Conflict 1 of 1 111 %%%%%%% Changes from base to side #1 112 -base 113 +x 114 +++++++ Contents of side #2 115 n 116 >>>>>>> 117 "###); 118 119 // Unmatched paths should generate warnings 120 let (_stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["chmod", "x", "nonexistent", "file"]); 121 insta::assert_snapshot!(stderr, @r###" 122 Warning: No matching entries for paths: nonexistent 123 Working copy now at: yostqsxw e5912d62 conflict | (conflict) conflict 124 Parent commit : royxmykx 427fbd2f x | x 125 Parent commit : zsuskuln 3f83a26d n | n 126 Added 0 files, modified 1 files, removed 0 files 127 There are unresolved conflicts at these paths: 128 file 2-sided conflict including an executable 129 "###); 130} 131 132// TODO: Test demonstrating that conflicts whose *base* is not a file are 133// chmod-dable 134 135#[test] 136fn test_chmod_file_dir_deletion_conflicts() { 137 let test_env = TestEnvironment::default(); 138 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 139 let repo_path = test_env.env_root().join("repo"); 140 141 create_commit(&test_env, &repo_path, "base", &[], &[("file", "base\n")]); 142 create_commit(&test_env, &repo_path, "file", &["base"], &[("file", "a\n")]); 143 144 create_commit(&test_env, &repo_path, "deletion", &["base"], &[]); 145 std::fs::remove_file(repo_path.join("file")).unwrap(); 146 147 create_commit(&test_env, &repo_path, "dir", &["base"], &[]); 148 std::fs::remove_file(repo_path.join("file")).unwrap(); 149 std::fs::create_dir(repo_path.join("file")).unwrap(); 150 // Without a placeholder file, `jj` ignores an empty directory 151 std::fs::write(repo_path.join("file").join("placeholder"), "").unwrap(); 152 153 // Create a file-dir conflict and a file-deletion conflict 154 create_commit(&test_env, &repo_path, "file_dir", &["file", "dir"], &[]); 155 create_commit( 156 &test_env, 157 &repo_path, 158 "file_deletion", 159 &["file", "deletion"], 160 &[], 161 ); 162 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 163 @ file_deletion 164 ├─╮ 165 │ ◉ deletion 166 │ │ ◉ file_dir 167 ╭───┤ 168 │ │ ◉ dir 169 │ ├─╯ 170 ◉ │ file 171 ├─╯ 172 ◉ base 173174 "###); 175 176 // The file-dir conflict cannot be chmod-ed 177 let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree", "-r=file_dir"]); 178 insta::assert_snapshot!(stdout, 179 @r###" 180 file: Ok(Conflicted([Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(Tree(TreeId("133bb38fc4e4bf6b551f1f04db7e48f04cac2877")))])) 181 "###); 182 let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "-r=file_dir", "file"]); 183 insta::assert_snapshot!(stdout, 184 @r###" 185 Conflict: 186 Removing file with id df967b96a579e45a18b8251732d16804b2e56a55 187 Adding file with id 78981922613b2afb6025042ff6bd878ac1994e85 188 Adding tree with id 133bb38fc4e4bf6b551f1f04db7e48f04cac2877 189 "###); 190 let stderr = test_env.jj_cmd_failure(&repo_path, &["chmod", "x", "file", "-r=file_dir"]); 191 insta::assert_snapshot!(stderr, @r###" 192 Error: Some of the sides of the conflict are not files at 'file'. 193 "###); 194 195 // The file_deletion conflict can be chmod-ed 196 let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree", "-r=file_deletion"]); 197 insta::assert_snapshot!(stdout, 198 @r###" 199 file: Ok(Conflicted([Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), None])) 200 "###); 201 let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "-r=file_deletion", "file"]); 202 insta::assert_snapshot!(stdout, 203 @r###" 204 <<<<<<< Conflict 1 of 1 205 +++++++ Contents of side #1 206 a 207 %%%%%%% Changes from base to side #2 208 -base 209 >>>>>>> 210 "###); 211 let (stdout, stderr) = 212 test_env.jj_cmd_ok(&repo_path, &["chmod", "x", "file", "-r=file_deletion"]); 213 insta::assert_snapshot!(stdout, @""); 214 insta::assert_snapshot!(stderr, @r###" 215 New conflicts appeared in these commits: 216 kmkuslsw 1b2ef84c file_deletion | (conflict) file_deletion 217 To resolve the conflicts, start by updating to it: 218 jj new kmkuslswpqwq 219 Then use `jj resolve`, or edit the conflict markers in the file directly. 220 Once the conflicts are resolved, you may want inspect the result with `jj diff`. 221 Then run `jj squash` to move the resolution into the conflicted commit. 222 Working copy now at: kmkuslsw 1b2ef84c file_deletion | (conflict) file_deletion 223 Parent commit : zsuskuln c51c9c55 file | file 224 Parent commit : royxmykx 6b18b3c1 deletion | deletion 225 Added 0 files, modified 1 files, removed 0 files 226 There are unresolved conflicts at these paths: 227 file 2-sided conflict including 1 deletion and an executable 228 "###); 229 let stdout = test_env.jj_cmd_success(&repo_path, &["debug", "tree", "-r=file_deletion"]); 230 insta::assert_snapshot!(stdout, 231 @r###" 232 file: Ok(Conflicted([Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: true }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: true }), None])) 233 "###); 234 let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "-r=file_deletion", "file"]); 235 insta::assert_snapshot!(stdout, 236 @r###" 237 <<<<<<< Conflict 1 of 1 238 +++++++ Contents of side #1 239 a 240 %%%%%%% Changes from base to side #2 241 -base 242 >>>>>>> 243 "###); 244}