1package bugcmd
  2
  3import (
  4	"fmt"
  5	"os"
  6	"strings"
  7	"testing"
  8	"time"
  9
 10	"github.com/stretchr/testify/require"
 11
 12	"github.com/MichaelMure/git-bug/commands/bug/testenv"
 13	"github.com/MichaelMure/git-bug/commands/cmdtest"
 14	"github.com/MichaelMure/git-bug/commands/execenv"
 15)
 16
 17func TestBugComment(t *testing.T) {
 18	const golden = "testdata/comment/message-only"
 19
 20	env, bug := testenv.NewTestEnvAndBug(t)
 21
 22	require.NoError(t, runBugComment(env, []string{bug.Human()}))
 23
 24	requireCommentsEqual(t, golden, env)
 25}
 26
 27const gitDateFormat = "Mon Jan 2 15:04:05 2006 -0700"
 28
 29type parsedComment struct {
 30	author  string
 31	id      string
 32	date    time.Time
 33	message string
 34}
 35
 36type parseFunc func(*parsedComment, string)
 37
 38type commentParser struct {
 39	t        *testing.T
 40	fn       parseFunc
 41	comments []parsedComment
 42}
 43
 44func parseComments(t *testing.T, env *execenv.Env) []parsedComment {
 45	t.Helper()
 46
 47	parser := &commentParser{
 48		t:        t,
 49		comments: []parsedComment{},
 50	}
 51
 52	comment := &parsedComment{}
 53	parser.fn = parser.parseAuthor
 54
 55	for _, line := range strings.Split(env.Out.String(), "\n") {
 56		parser.fn(comment, line)
 57	}
 58
 59	parser.comments = append(parser.comments, *comment)
 60
 61	return parser.comments
 62}
 63
 64func (p *commentParser) parseAuthor(comment *parsedComment, line string) {
 65	p.t.Helper()
 66
 67	tkns := strings.Split(line, ": ")
 68	require.Len(p.t, tkns, 2)
 69	require.Equal(p.t, "Author", tkns[0])
 70
 71	comment.author = tkns[1]
 72	p.fn = p.parseID
 73}
 74
 75func (p *commentParser) parseID(comment *parsedComment, line string) {
 76	p.t.Helper()
 77
 78	tkns := strings.Split(line, ": ")
 79	require.Len(p.t, tkns, 2)
 80	require.Equal(p.t, "Id", tkns[0])
 81
 82	comment.id = tkns[1]
 83	p.fn = p.parseDate
 84}
 85
 86func (p *commentParser) parseDate(comment *parsedComment, line string) {
 87	p.t.Helper()
 88
 89	tkns := strings.Split(line, ": ")
 90	require.Len(p.t, tkns, 2)
 91	require.Equal(p.t, "Date", tkns[0])
 92
 93	date, err := time.Parse(gitDateFormat, tkns[1])
 94	require.NoError(p.t, err)
 95
 96	comment.date = date
 97	p.fn = p.parseMessage
 98}
 99
100func (p *commentParser) parseMessage(comment *parsedComment, line string) {
101	p.t.Helper()
102
103	if strings.HasPrefix(line, "Author: ") {
104		p.comments = append(p.comments, *comment)
105		comment = &parsedComment{}
106		p.parseAuthor(comment, line)
107
108		return
109	}
110
111	require.True(p.t, line == "" || strings.HasPrefix(line, "    "))
112
113	comment.message = strings.Join([]string{comment.message, line}, "\n")
114}
115
116func normalizeParsedComments(t *testing.T, comments []parsedComment) []parsedComment {
117	t.Helper()
118
119	prefix := 0x1234567
120	date, err := time.Parse(gitDateFormat, "Fri Aug 19 07:00:00 2022 +1900")
121	require.NoError(t, err)
122
123	var out []parsedComment
124
125	for i, comment := range comments {
126		comment.id = fmt.Sprintf("%7x", prefix+i)
127		comment.date = date.Add(time.Duration(i) * time.Minute)
128		out = append(out, comment)
129	}
130
131	return out
132}
133
134func requireCommentsEqual(t *testing.T, golden string, env *execenv.Env) {
135	t.Helper()
136
137	const goldenFilePattern = "%s-%d-golden.txt"
138
139	comments := parseComments(t, env)
140	comments = normalizeParsedComments(t, comments)
141
142	if *cmdtest.Update {
143		t.Log("Got here")
144		for i, comment := range comments {
145			fileName := fmt.Sprintf(goldenFilePattern, golden, i)
146			require.NoError(t, os.WriteFile(fileName, []byte(comment.message), 0644))
147		}
148	}
149
150	prefix := 0x1234567
151	date, err := time.Parse(gitDateFormat, "Fri Aug 19 07:00:00 2022 +1900")
152	require.NoError(t, err)
153
154	for i, comment := range comments {
155		require.Equal(t, "John Doe", comment.author)
156		require.Equal(t, fmt.Sprintf("%7x", prefix+i), comment.id)
157		require.Equal(t, date.Add(time.Duration(i)*time.Minute), comment.date)
158
159		fileName := fmt.Sprintf(goldenFilePattern, golden, i)
160		exp, err := os.ReadFile(fileName)
161		require.NoError(t, err)
162		require.Equal(t, strings.ReplaceAll(string(exp), "\r", ""), strings.ReplaceAll(comment.message, "\r", ""))
163	}
164}