Merge remote-tracking branch 'origin/master' into diff-cleanup
[idea/community.git] / plugins / git4idea / tests / git4idea / test / GitScenarios.java
1 package git4idea.test;
2
3 import com.intellij.openapi.util.io.FileUtil;
4 import com.intellij.openapi.vcs.Executor;
5 import git4idea.repo.GitRepository;
6
7 import java.io.File;
8 import java.io.IOException;
9 import java.util.Collection;
10
11 /**
12  * Create popular scenarios used in multiple tests, for example:
13  * - create a branch and commit something there;
14  * - make some unmerged files in the working tree;
15  * - make the situation when local changes would be overwritten by merge.
16  */
17 public class GitScenarios {
18   private static final String BRANCH_FOR_UNMERGED_CONFLICTS = "unmerged_files_branch_" + Math.random();
19
20   public static final MergeContent LOCAL_CHANGES_OVERWRITTEN_BY = new MergeContent("common content\ncommon content\ncommon content\n",
21                                                                                     "line with branch changes\n",
22                                                                                     "line with master changes");
23
24   /**
25    * Create a branch with a commit and return back to master.
26    */
27   public static void branchWithCommit(GitRepository repository, String name, String file, String content, boolean returnToMaster) {
28     GitExecutor.cd(repository);
29     GitExecutor.git("checkout -b " + name);
30     Executor.touch(file, content);
31     GitExecutor.git("add " + file);
32     GitExecutor.git("commit -m branch_content");
33
34     if (returnToMaster) {
35       GitExecutor.git("checkout master");
36     }
37   }
38
39   /**
40    * Create a branch with a commit and return back to master.
41    */
42   public static void branchWithCommit(GitRepository repository, String name, String file, String content) {
43     GitScenarios.branchWithCommit(repository, name, file, content, true);
44   }
45
46   /**
47    * Create a branch with a commit and return back to master.
48    */
49   public static void branchWithCommit(GitRepository repository, String name, String file) {
50     GitScenarios.branchWithCommit(repository, name, file, "branch content", true);
51   }
52
53   /**
54    * Create a branch with a commit and return back to master.
55    */
56   public static void branchWithCommit(GitRepository repository, String name) {
57     GitScenarios.branchWithCommit(repository, name, "branch_file.txt", "branch content", true);
58   }
59
60   /**
61    * Create a branch with a commit and return back to master.
62    */
63   public static void branchWithCommit(Collection<GitRepository> repositories, final String name, final String file, final String content) {
64     for (GitRepository repository : repositories) {
65       branchWithCommit(repository, name, file, content);
66     }
67   }
68
69   /**
70    * Create a branch with a commit and return back to master.
71    */
72   public static void branchWithCommit(Collection<GitRepository> repositories, String name, String file) {
73     GitScenarios.branchWithCommit(repositories, name, file, "branch content");
74   }
75
76   /**
77    * Create a branch with a commit and return back to master.
78    */
79   public static void branchWithCommit(Collection<GitRepository> repositories, String name) {
80     GitScenarios.branchWithCommit(repositories, name, "branch_file.txt", "branch content");
81   }
82
83   /**
84    * Make an unmerged file in the repository.
85    */
86   public static String unmergedFiles(GitRepository repository) {
87     conflict(repository, BRANCH_FOR_UNMERGED_CONFLICTS, "unmerged.txt");
88     GitExecutor.git("merge " + BRANCH_FOR_UNMERGED_CONFLICTS, true);
89     return GitExecutor.git("branch -D " + BRANCH_FOR_UNMERGED_CONFLICTS);
90   }
91
92   /**
93    * Creates a branch with the given name, and produces conflicted content in a file between this branch and master.
94    * Branch must not exist at this point.
95    */
96   public static String conflict(GitRepository repository, String branch, String file) {
97     assert !branchExists(repository, branch) : "Branch [" + branch + "] shouldn\'t exist for this scenario";
98
99     GitExecutor.cd(repository);
100
101     Executor.touch(file, "initial content");
102     GitExecutor.git("add " + file);
103     GitExecutor.git("commit -m initial_content");
104
105     GitExecutor.git("checkout -b " + branch);
106     Executor.echo(file, "branch content");
107     GitExecutor.git("commit -am branch_content");
108
109     GitExecutor.git("checkout master");
110     Executor.echo(file, "master content");
111     return GitExecutor.git("commit -am master_content");
112   }
113
114   /**
115    * Creates a branch with the given name, and produces conflicted content in a file between this branch and master.
116    * Branch must not exist at this point.
117    */
118   public static String conflict(GitRepository repository, String branch) {
119     return GitScenarios.conflict(repository, branch, "conflict.txt");
120   }
121
122   /**
123    * Create an untracked file in master and a tracked file with the same name in the branch.
124    * This produces the "some untracked files would be overwritten by..." error when trying to checkout or merge.
125    * Branch with the given name shall exist.
126    */
127   public static void untrackedFileOverwrittenBy(GitRepository repository, String branch, Collection<String> fileNames) {
128     GitExecutor.cd(repository);
129     GitExecutor.git("checkout " + branch);
130
131     for (String it : fileNames) {
132       Executor.touch(it, "branch content");
133       GitExecutor.git("add " + it);
134     }
135
136
137     GitExecutor.git("commit -m untracked_files");
138     GitExecutor.git("checkout master");
139
140     for (String it : fileNames) {
141       Executor.touch(it, "master content");
142     }
143   }
144
145   /**
146    * Creates a file in both master and branch so that the content differs, but can be merged without conflicts.
147    * That way, git checkout/merge will fail with "local changes would be overwritten by checkout/merge",
148    * but smart checkout/merge (stash-checkout/merge-unstash) would succeed without conflicts.
149    * <p/>
150    * NB: the branch should not exist before this is called!
151    */
152   public static void localChangesOverwrittenByWithoutConflict(GitRepository repository, String branch, Collection<String> fileNames) {
153     GitExecutor.cd(repository);
154
155     for (String it : fileNames) {
156       Executor.echo(it, LOCAL_CHANGES_OVERWRITTEN_BY.initial);
157       GitExecutor.git("add " + it);
158     }
159
160     GitExecutor.git("commit -m initial_changes");
161
162     GitExecutor.git("checkout -b " + branch);
163     for (String it : fileNames) {
164       prepend(it, LOCAL_CHANGES_OVERWRITTEN_BY.branchLine);
165       GitExecutor.git("add " + it);
166     }
167
168     GitExecutor.git("commit -m branch_changes");
169
170     GitExecutor.git("checkout master");
171     for (String it : fileNames) {
172       append1(it, LOCAL_CHANGES_OVERWRITTEN_BY.masterLine);
173     }
174   }
175
176   public static void append1(String fileName, String content) {
177     Executor.echo(fileName, content);
178   }
179
180   public static void prepend(String fileName, final String content) {
181     String previousContent = Executor.cat(fileName);
182     try {
183       FileUtil.writeToFile(new File(Executor.pwd(), fileName), content + previousContent);
184     }
185     catch (IOException e) {
186       throw new RuntimeException(e);
187     }
188   }
189
190   public static String commit(GitRepository repository, String file) {
191     GitExecutor.cd(repository);
192     Executor.touch(file);
193     GitExecutor.git("add " + file);
194     return GitExecutor.git("commit -m just_a_commit");
195   }
196
197   public static String commit(GitRepository repository) {
198     return GitScenarios.commit(repository, "just_a_file_" + String.valueOf(Math.random()) + ".txt");
199   }
200
201   public static boolean branchExists(GitRepository repo, String branch) {
202     return GitExecutor.git(repo, "branch").contains(branch);
203   }
204
205   public static boolean branchExists(String branch) {
206     return GitScenarios.branchExists(null, branch);
207   }
208
209   public static void checkoutOrCreate(GitRepository repository, String branch) {
210     if (branch.equals("master") || branchExists(repository, branch)) {
211       GitExecutor.git("checkout " + branch);
212     }
213     else {
214       GitExecutor.git("checkout -b " + branch);
215     }
216   }
217
218   public static void checkoutOrCreate(String branch) {
219     GitScenarios.checkoutOrCreate(null, branch);
220   }
221
222   public static void checkout(String branch) {
223     GitExecutor.git("checkout " + branch);
224   }
225
226   public static class MergeContent {
227     public final String initial;
228     public final String branchLine;
229     public final String masterLine;
230     public MergeContent(String initialContent, String branchLine, String masterLine) {
231
232       initial = initialContent;
233       this.branchLine = branchLine;
234       this.masterLine = masterLine;
235     }
236   }
237 }