1package git_test
2
3import (
4	"io/ioutil"
5	"path/filepath"
6	"strings"
7	"testing"
8
9	"github.com/git-town/git-town/src/git"
10	"github.com/git-town/git-town/test"
11	"github.com/stretchr/testify/assert"
12)
13
14func TestRunner_AddRemote(t *testing.T) {
15	runner := test.CreateTestGitTownRepo(t).Runner
16	err := runner.AddRemote("foo", "bar")
17	assert.NoError(t, err)
18	remotes, err := runner.Remotes()
19	assert.NoError(t, err)
20	assert.Equal(t, []string{"foo"}, remotes)
21}
22
23func TestRunner_CheckoutBranch(t *testing.T) {
24	runner := test.CreateRepo(t).Runner
25	err := runner.CreateBranch("branch1", "master")
26	assert.NoError(t, err)
27	err = runner.CheckoutBranch("branch1")
28	assert.NoError(t, err)
29	currentBranch, err := runner.CurrentBranch()
30	assert.NoError(t, err)
31	assert.Equal(t, "branch1", currentBranch)
32	err = runner.CheckoutBranch("master")
33	assert.NoError(t, err)
34	currentBranch, err = runner.CurrentBranch()
35	assert.NoError(t, err)
36	assert.Equal(t, "master", currentBranch)
37}
38
39func TestRunner_Commits(t *testing.T) {
40	runner := test.CreateRepo(t).Runner
41	err := runner.CreateCommit(git.Commit{
42		Branch:      "master",
43		FileName:    "file1",
44		FileContent: "hello",
45		Message:     "first commit",
46	})
47	assert.NoError(t, err)
48	err = runner.CreateCommit(git.Commit{
49		Branch:      "master",
50		FileName:    "file2",
51		FileContent: "hello again",
52		Message:     "second commit",
53	})
54	assert.NoError(t, err)
55	commits, err := runner.Commits([]string{"FILE NAME", "FILE CONTENT"})
56	assert.NoError(t, err)
57	assert.Len(t, commits, 2)
58	assert.Equal(t, "master", commits[0].Branch)
59	assert.Equal(t, "file1", commits[0].FileName)
60	assert.Equal(t, "hello", commits[0].FileContent)
61	assert.Equal(t, "first commit", commits[0].Message)
62	assert.Equal(t, "master", commits[1].Branch)
63	assert.Equal(t, "file2", commits[1].FileName)
64	assert.Equal(t, "hello again", commits[1].FileContent)
65	assert.Equal(t, "second commit", commits[1].Message)
66}
67
68func TestRunner_Configuration(t *testing.T) {
69	runner := test.CreateRepo(t).Runner
70	config := runner.Config
71	assert.NotNil(t, config, "first path: new config")
72	config = runner.Config
73	assert.NotNil(t, config, "second path: cached config")
74}
75
76func TestRunner_ConnectTrackingBranch(t *testing.T) {
77	// replicating the situation this is used in,
78	// connecting branches of repos with the same commits in them
79	origin := test.CreateRepo(t)
80	repoDir := filepath.Join(test.CreateTempDir(t), "repo") // need a non-existing directory
81	err := test.CopyDirectory(origin.WorkingDir(), repoDir)
82	assert.NoError(t, err)
83	runner := test.NewRepo(repoDir, repoDir, "").Runner
84	err = runner.AddRemote("origin", origin.WorkingDir())
85	assert.NoError(t, err)
86	err = runner.Fetch()
87	assert.NoError(t, err)
88	err = runner.ConnectTrackingBranch("master")
89	assert.NoError(t, err)
90	err = runner.PushBranch()
91	assert.NoError(t, err)
92}
93
94func TestRunner_CreateBranch(t *testing.T) {
95	runner := test.CreateRepo(t).Runner
96	err := runner.CreateBranch("branch1", "master")
97	assert.NoError(t, err)
98	currentBranch, err := runner.CurrentBranch()
99	assert.NoError(t, err)
100	assert.Equal(t, "master", currentBranch)
101	branches, err := runner.LocalBranchesMainFirst()
102	assert.NoError(t, err)
103	assert.Equal(t, []string{"branch1", "master"}, branches)
104}
105
106func TestRunner_CreateChildFeatureBranch(t *testing.T) {
107	runner := test.CreateTestGitTownRepo(t).Runner
108	err := runner.CreateFeatureBranch("f1")
109	assert.NoError(t, err)
110	err = runner.CreateChildFeatureBranch("f1a", "f1")
111	assert.NoError(t, err)
112	res, err := runner.Run("git", "town", "config")
113	assert.NoError(t, err)
114	has := strings.Contains(res.OutputSanitized(), "Branch Ancestry:\n  main\n    f1\n      f1a")
115	assert.True(t, has)
116}
117
118func TestRunner_CreateCommit(t *testing.T) {
119	runner := test.CreateRepo(t).Runner
120	err := runner.CreateCommit(git.Commit{
121		Branch:      "master",
122		FileName:    "hello.txt",
123		FileContent: "hello world",
124		Message:     "test commit",
125	})
126	assert.NoError(t, err)
127	commits, err := runner.Commits([]string{"FILE NAME", "FILE CONTENT"})
128	assert.NoError(t, err)
129	assert.Len(t, commits, 1)
130	assert.Equal(t, "hello.txt", commits[0].FileName)
131	assert.Equal(t, "hello world", commits[0].FileContent)
132	assert.Equal(t, "test commit", commits[0].Message)
133	assert.Equal(t, "master", commits[0].Branch)
134}
135
136func TestRunner_CreateCommit_Author(t *testing.T) {
137	runner := test.CreateRepo(t).Runner
138	err := runner.CreateCommit(git.Commit{
139		Branch:      "master",
140		FileName:    "hello.txt",
141		FileContent: "hello world",
142		Message:     "test commit",
143		Author:      "developer <developer@example.com>",
144	})
145	assert.NoError(t, err)
146	commits, err := runner.Commits([]string{"FILE NAME", "FILE CONTENT"})
147	assert.NoError(t, err)
148	assert.Len(t, commits, 1)
149	assert.Equal(t, "hello.txt", commits[0].FileName)
150	assert.Equal(t, "hello world", commits[0].FileContent)
151	assert.Equal(t, "test commit", commits[0].Message)
152	assert.Equal(t, "master", commits[0].Branch)
153	assert.Equal(t, "developer <developer@example.com>", commits[0].Author)
154}
155
156func TestRunner_CreateFeatureBranch(t *testing.T) {
157	runner := test.CreateTestGitTownRepo(t).Runner
158	err := runner.CreateFeatureBranch("f1")
159	assert.NoError(t, err)
160	runner.Config.Reload()
161	assert.True(t, runner.Config.IsFeatureBranch("f1"))
162	assert.Equal(t, []string{"main"}, runner.Config.GetAncestorBranches("f1"))
163}
164
165func TestRunner_CreateFeatureBranchNoParent(t *testing.T) {
166	runner := test.CreateTestGitTownRepo(t).Runner
167	err := runner.CreateFeatureBranchNoParent("f1")
168	assert.NoError(t, err)
169	runner.Config.Reload()
170	assert.True(t, runner.Config.IsFeatureBranch("f1"))
171	assert.Equal(t, []string(nil), runner.Config.GetAncestorBranches("f1"))
172}
173
174func TestRunner_CreateFile(t *testing.T) {
175	runner := test.CreateRepo(t).Runner
176	err := runner.CreateFile("filename", "content")
177	assert.Nil(t, err, "cannot create file in repo")
178	content, err := ioutil.ReadFile(filepath.Join(runner.WorkingDir(), "filename"))
179	assert.Nil(t, err, "cannot read file")
180	assert.Equal(t, "content", string(content))
181}
182
183func TestRunner_CreateFile_InSubFolder(t *testing.T) {
184	runner := test.CreateRepo(t).Runner
185	err := runner.CreateFile("folder/filename", "content")
186	assert.Nil(t, err, "cannot create file in repo")
187	content, err := ioutil.ReadFile(filepath.Join(runner.WorkingDir(), "folder/filename"))
188	assert.Nil(t, err, "cannot read file")
189	assert.Equal(t, "content", string(content))
190}
191
192func TestRunner_CreatePerennialBranches(t *testing.T) {
193	runner := test.CreateTestGitTownRepo(t).Runner
194	err := runner.CreatePerennialBranches("p1", "p2")
195	assert.NoError(t, err)
196	branches, err := runner.LocalBranchesMainFirst()
197	assert.NoError(t, err)
198	assert.Equal(t, []string{"main", "master", "p1", "p2"}, branches)
199	runner.Config.Reload()
200	assert.True(t, runner.Config.IsPerennialBranch("p1"))
201	assert.True(t, runner.Config.IsPerennialBranch("p2"))
202}
203
204func TestRunner_CurrentBranch(t *testing.T) {
205	runner := test.CreateRepo(t).Runner
206	err := runner.CheckoutBranch("master")
207	assert.NoError(t, err)
208	err = runner.CreateBranch("b1", "master")
209	assert.NoError(t, err)
210	err = runner.CheckoutBranch("b1")
211	assert.NoError(t, err)
212	branch, err := runner.CurrentBranch()
213	assert.NoError(t, err)
214	assert.Equal(t, "b1", branch)
215	err = runner.CheckoutBranch("master")
216	assert.NoError(t, err)
217	branch, err = runner.CurrentBranch()
218	assert.NoError(t, err)
219	assert.Equal(t, "master", branch)
220}
221
222func TestRunner_Fetch(t *testing.T) {
223	runner := test.CreateRepo(t).Runner
224	origin := test.CreateRepo(t)
225	err := runner.AddRemote("origin", origin.WorkingDir())
226	assert.NoError(t, err)
227	err = runner.Fetch()
228	assert.NoError(t, err)
229}
230
231func TestRunner_FileContentInCommit(t *testing.T) {
232	runner := test.CreateRepo(t).Runner
233	err := runner.CreateCommit(git.Commit{
234		Branch:      "master",
235		FileName:    "hello.txt",
236		FileContent: "hello world",
237		Message:     "commit",
238	})
239	assert.NoError(t, err)
240	commits, err := runner.CommitsInBranch("master", []string{})
241	assert.NoError(t, err)
242	assert.Len(t, commits, 1)
243	content, err := runner.FileContentInCommit(commits[0].SHA, "hello.txt")
244	assert.NoError(t, err)
245	assert.Equal(t, "hello world", content)
246}
247
248func TestRunner_FilesInCommit(t *testing.T) {
249	runner := test.CreateRepo(t).Runner
250	err := runner.CreateFile("f1.txt", "one")
251	assert.NoError(t, err)
252	err = runner.CreateFile("f2.txt", "two")
253	assert.NoError(t, err)
254	err = runner.StageFiles("f1.txt", "f2.txt")
255	assert.NoError(t, err)
256	err = runner.CommitStagedChanges("stuff")
257	assert.NoError(t, err)
258	commits, err := runner.Commits([]string{})
259	assert.NoError(t, err)
260	assert.Len(t, commits, 1)
261	fileNames, err := runner.FilesInCommit(commits[0].SHA)
262	assert.NoError(t, err)
263	assert.Equal(t, []string{"f1.txt", "f2.txt"}, fileNames)
264}
265
266func TestRunner_HasBranchesOutOfSync_synced(t *testing.T) {
267	env, err := test.NewStandardGitEnvironment(test.CreateTempDir(t))
268	assert.NoError(t, err)
269	runner := env.DevRepo.Runner
270	err = runner.CreateBranch("branch1", "main")
271	assert.NoError(t, err)
272	err = runner.CheckoutBranch("branch1")
273	assert.NoError(t, err)
274	err = runner.CreateFile("file1", "content")
275	assert.NoError(t, err)
276	err = runner.StageFiles("file1")
277	assert.NoError(t, err)
278	err = runner.CommitStagedChanges("stuff")
279	assert.NoError(t, err)
280	err = runner.PushBranchSetUpstream("branch1")
281	assert.NoError(t, err)
282	have, err := runner.HasBranchesOutOfSync()
283	assert.NoError(t, err)
284	assert.False(t, have)
285}
286
287func TestRunner_HasBranchesOutOfSync_branchAhead(t *testing.T) {
288	env, err := test.NewStandardGitEnvironment(test.CreateTempDir(t))
289	assert.NoError(t, err)
290	runner := env.DevRepo.Runner
291	err = runner.CreateBranch("branch1", "main")
292	assert.NoError(t, err)
293	err = runner.PushBranch()
294	assert.NoError(t, err)
295	err = runner.CreateFile("file1", "content")
296	assert.NoError(t, err)
297	err = runner.StageFiles("file1")
298	assert.NoError(t, err)
299	err = runner.CommitStagedChanges("stuff")
300	assert.NoError(t, err)
301	have, err := runner.HasBranchesOutOfSync()
302	assert.NoError(t, err)
303	assert.True(t, have)
304}
305
306func TestRunner_HasBranchesOutOfSync_branchBehind(t *testing.T) {
307	env, err := test.NewStandardGitEnvironment(test.CreateTempDir(t))
308	assert.NoError(t, err)
309	err = env.DevRepo.CreateBranch("branch1", "main")
310	assert.NoError(t, err)
311	err = env.DevRepo.PushBranch()
312	assert.NoError(t, err)
313	err = env.OriginRepo.CheckoutBranch("main")
314	assert.NoError(t, err)
315	err = env.OriginRepo.CreateFile("file1", "content")
316	assert.NoError(t, err)
317	err = env.OriginRepo.StageFiles("file1")
318	assert.NoError(t, err)
319	err = env.OriginRepo.CommitStagedChanges("stuff")
320	assert.NoError(t, err)
321	err = env.OriginRepo.CheckoutBranch("master")
322	assert.NoError(t, err)
323	err = env.DevRepo.Fetch()
324	assert.NoError(t, err)
325	have, err := env.DevRepo.Runner.HasBranchesOutOfSync()
326	assert.NoError(t, err)
327	assert.True(t, have)
328}
329
330func TestRunner_HasGitTownConfigNow(t *testing.T) {
331	runner := test.CreateRepo(t).Runner
332	res, err := runner.HasGitTownConfigNow()
333	assert.NoError(t, err)
334	assert.False(t, res)
335	err = runner.CreateBranch("main", "master")
336	assert.NoError(t, err)
337	err = runner.CreateFeatureBranch("foo")
338	assert.NoError(t, err)
339	res, err = runner.HasGitTownConfigNow()
340	assert.NoError(t, err)
341	assert.True(t, res)
342}
343
344func TestRunner_HasFile(t *testing.T) {
345	runner := test.CreateRepo(t).Runner
346	err := runner.CreateFile("f1.txt", "one")
347	assert.NoError(t, err)
348	has, err := runner.HasFile("f1.txt", "one")
349	assert.NoError(t, err)
350	assert.True(t, has)
351	_, err = runner.HasFile("f1.txt", "zonk")
352	assert.Error(t, err)
353	_, err = runner.HasFile("zonk.txt", "one")
354	assert.Error(t, err)
355}
356func TestRunner_HasLocalBranch(t *testing.T) {
357	origin := test.CreateRepo(t)
358	repoDir := test.CreateTempDir(t)
359	repo, err := origin.Clone(repoDir)
360	assert.NoError(t, err)
361	err = repo.CreateBranch("b1", "master")
362	assert.NoError(t, err)
363	err = repo.CreateBranch("b2", "master")
364	assert.NoError(t, err)
365	has, err := repo.HasLocalBranch("b1")
366	assert.NoError(t, err)
367	assert.True(t, has)
368	has, err = repo.HasLocalBranch("b2")
369	assert.NoError(t, err)
370	assert.True(t, has)
371	has, err = repo.HasLocalBranch("b3")
372	assert.NoError(t, err)
373	assert.False(t, has)
374}
375
376func TestRunner_HasOpenChanges(t *testing.T) {
377	runner := test.CreateRepo(t).Runner
378	has, err := runner.HasOpenChanges()
379	assert.NoError(t, err)
380	assert.False(t, has)
381	err = runner.CreateFile("foo", "bar")
382	assert.NoError(t, err)
383	has, err = runner.HasOpenChanges()
384	assert.NoError(t, err)
385	assert.True(t, has)
386}
387
388func TestRunner_HasRebaseInProgress(t *testing.T) {
389	runner := test.CreateRepo(t).Runner
390	has, err := runner.HasRebaseInProgress()
391	assert.NoError(t, err)
392	assert.False(t, has)
393}
394
395func TestRunner_HasRemote(t *testing.T) {
396	origin := test.CreateRepo(t)
397	repoDir := test.CreateTempDir(t)
398	repo, err := origin.Clone(repoDir)
399	assert.NoError(t, err)
400	has, err := repo.Runner.HasRemote("origin")
401	assert.NoError(t, err)
402	assert.True(t, has)
403	has, err = repo.Runner.HasRemote("zonk")
404	assert.NoError(t, err)
405	assert.False(t, has)
406}
407
408func TestRunner_HasTrackingBranch(t *testing.T) {
409	origin := test.CreateRepo(t)
410	err := origin.CreateBranch("b1", "master")
411	assert.NoError(t, err)
412	repoDir := test.CreateTempDir(t)
413	repo, err := origin.Clone(repoDir)
414	assert.NoError(t, err)
415	runner := repo.Runner
416	err = runner.CheckoutBranch("b1")
417	assert.NoError(t, err)
418	err = runner.CreateBranch("b2", "master")
419	assert.NoError(t, err)
420	has, err := runner.HasTrackingBranch("b1")
421	assert.NoError(t, err)
422	assert.True(t, has)
423	has, err = runner.HasTrackingBranch("b2")
424	assert.NoError(t, err)
425	assert.False(t, has)
426	has, err = runner.HasTrackingBranch("b3")
427	assert.NoError(t, err)
428	assert.False(t, has)
429}
430
431func TestRunner_LocalBranches(t *testing.T) {
432	origin := test.CreateRepo(t)
433	repoDir := test.CreateTempDir(t)
434	repo, err := origin.Clone(repoDir)
435	assert.NoError(t, err)
436	err = repo.CreateBranch("b1", "master")
437	assert.NoError(t, err)
438	err = repo.CreateBranch("b2", "master")
439	assert.NoError(t, err)
440	err = origin.CreateBranch("b3", "master")
441	assert.NoError(t, err)
442	err = repo.Fetch()
443	assert.NoError(t, err)
444	branches, err := repo.Runner.LocalBranchesMainFirst()
445	assert.NoError(t, err)
446	assert.Equal(t, []string{"b1", "b2", "master"}, branches)
447}
448
449func TestRunner_LocalAndRemoteBranches(t *testing.T) {
450	origin := test.CreateRepo(t)
451	repoDir := test.CreateTempDir(t)
452	repo, err := origin.Clone(repoDir)
453	assert.NoError(t, err)
454	err = repo.CreateBranch("b1", "master")
455	assert.NoError(t, err)
456	err = repo.CreateBranch("b2", "master")
457	assert.NoError(t, err)
458	err = origin.CreateBranch("b3", "master")
459	assert.NoError(t, err)
460	err = repo.Fetch()
461	assert.NoError(t, err)
462	branches, err := repo.Runner.LocalAndRemoteBranches()
463	assert.NoError(t, err)
464	assert.Equal(t, []string{"b1", "b2", "b3", "master"}, branches)
465}
466
467func TestRunner_PreviouslyCheckedOutBranch(t *testing.T) {
468	runner := test.CreateRepo(t).Runner
469	err := runner.CreateBranch("feature1", "master")
470	assert.NoError(t, err)
471	err = runner.CreateBranch("feature2", "master")
472	assert.NoError(t, err)
473	err = runner.CheckoutBranch("feature1")
474	assert.NoError(t, err)
475	err = runner.CheckoutBranch("feature2")
476	assert.NoError(t, err)
477	have, err := runner.PreviouslyCheckedOutBranch()
478	assert.NoError(t, err)
479	assert.Equal(t, "feature1", have)
480}
481
482func TestRunner_PushBranch(t *testing.T) {
483	runner := test.CreateRepo(t).Runner
484	origin := test.CreateRepo(t)
485	err := runner.AddRemote("origin", origin.WorkingDir())
486	assert.NoError(t, err)
487	err = runner.CreateBranch("b1", "master")
488	assert.NoError(t, err)
489	err = runner.PushBranchSetUpstream("b1")
490	assert.NoError(t, err)
491	branches, err := origin.LocalBranchesMainFirst()
492	assert.NoError(t, err)
493	assert.Equal(t, []string{"b1", "master"}, branches)
494}
495
496func TestRunner_RemoteBranches(t *testing.T) {
497	origin := test.CreateRepo(t)
498	repoDir := test.CreateTempDir(t)
499	repo, err := origin.Clone(repoDir)
500	assert.NoError(t, err)
501	err = repo.CreateBranch("b1", "master")
502	assert.NoError(t, err)
503	err = repo.CreateBranch("b2", "master")
504	assert.NoError(t, err)
505	err = origin.CreateBranch("b3", "master")
506	assert.NoError(t, err)
507	err = repo.Fetch()
508	assert.NoError(t, err)
509	branches, err := repo.Runner.RemoteBranches()
510	assert.NoError(t, err)
511	assert.Equal(t, []string{"origin/b3", "origin/master"}, branches)
512}
513
514func TestRunner_Remotes(t *testing.T) {
515	runner := test.CreateRepo(t).Runner
516	origin := test.CreateRepo(t)
517	err := runner.AddRemote("origin", origin.WorkingDir())
518	assert.NoError(t, err)
519	remotes, err := runner.Remotes()
520	assert.NoError(t, err)
521	assert.Equal(t, []string{"origin"}, remotes)
522}
523
524func TestRunner_RemoveBranch(t *testing.T) {
525	runner := test.CreateRepo(t).Runner
526	err := runner.CreateBranch("b1", "master")
527	assert.NoError(t, err)
528	branches, err := runner.LocalBranchesMainFirst()
529	assert.NoError(t, err)
530	assert.Equal(t, []string{"b1", "master"}, branches)
531	err = runner.RemoveBranch("b1")
532	assert.NoError(t, err)
533	branches, err = runner.LocalBranchesMainFirst()
534	assert.NoError(t, err)
535	assert.Equal(t, []string{"master"}, branches)
536}
537
538func TestRunner_RemoveRemote(t *testing.T) {
539	runner := test.CreateRepo(t).Runner
540	origin := test.CreateRepo(t)
541	err := runner.AddRemote("origin", origin.WorkingDir())
542	assert.NoError(t, err)
543	err = runner.RemoveRemote("origin")
544	assert.NoError(t, err)
545	remotes, err := runner.Remotes()
546	assert.NoError(t, err)
547	assert.Len(t, remotes, 0)
548}
549
550func TestRunner_SetRemote(t *testing.T) {
551	runner := test.CreateRepo(t).Runner
552	remotes, err := runner.Remotes()
553	assert.NoError(t, err)
554	assert.Equal(t, []string{}, remotes)
555	origin := test.CreateRepo(t)
556	err = runner.AddRemote("origin", origin.WorkingDir())
557	assert.NoError(t, err)
558	remotes, err = runner.Remotes()
559	assert.NoError(t, err)
560	assert.Equal(t, []string{"origin"}, remotes)
561}
562
563func TestRunner_ShaForCommit(t *testing.T) {
564	runner := test.CreateRepo(t).Runner
565	err := runner.CreateCommit(git.Commit{Branch: "master", FileName: "foo", FileContent: "bar", Message: "commit"})
566	assert.NoError(t, err)
567	sha, err := runner.ShaForCommit("commit")
568	assert.NoError(t, err)
569	assert.Len(t, sha, 40)
570}
571
572func TestRunner_StageFile(t *testing.T) {
573	runner := test.CreateRepo(t).Runner
574	err := runner.CreateFile("f1.txt", "one")
575	assert.NoError(t, err)
576}
577
578func TestRunner_Stash(t *testing.T) {
579	runner := test.CreateRepo(t).Runner
580	stashSize, err := runner.StashSize()
581	assert.NoError(t, err)
582	assert.Zero(t, stashSize)
583	err = runner.CreateFile("f1.txt", "hello")
584	assert.NoError(t, err)
585	err = runner.Stash()
586	assert.NoError(t, err)
587	stashSize, err = runner.StashSize()
588	assert.NoError(t, err)
589	assert.Equal(t, 1, stashSize)
590}
591
592func TestRunner_UncommittedFiles(t *testing.T) {
593	runner := test.CreateRepo(t).Runner
594	err := runner.CreateFile("f1.txt", "one")
595	assert.NoError(t, err)
596	err = runner.CreateFile("f2.txt", "two")
597	assert.NoError(t, err)
598	files, err := runner.UncommittedFiles()
599	assert.NoError(t, err)
600	assert.Equal(t, []string{"f1.txt", "f2.txt"}, files)
601}
602