mirror of
https://github.com/romdo/go-conver.git
synced 2026-02-19 08:16:40 +00:00
567 lines
14 KiB
Go
567 lines
14 KiB
Go
package commit
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func Test_parseHeader(t *testing.T) {
|
|
type args struct {
|
|
header []byte
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *Commit
|
|
errStr string
|
|
errIs []error
|
|
}{
|
|
{
|
|
name: "missing type",
|
|
args: args{header: []byte("add user sorting option")},
|
|
want: &Commit{Subject: "add user sorting option"},
|
|
errIs: []error{Err, ErrTypeMissing},
|
|
},
|
|
{
|
|
name: "missing type with scope",
|
|
args: args{
|
|
header: []byte("(user): add user sorting option"),
|
|
},
|
|
want: &Commit{Scope: "user", Subject: "add user sorting option"},
|
|
errStr: `type is missing`,
|
|
errIs: []error{Err, ErrType, ErrTypeMissing},
|
|
},
|
|
{
|
|
name: "type only",
|
|
args: args{header: []byte("feat: add user sorting option")},
|
|
want: &Commit{Type: "feat", Subject: "add user sorting option"},
|
|
},
|
|
{
|
|
name: "type and scope",
|
|
args: args{header: []byte("feat(user): add user sorting option")},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "type and breaking",
|
|
args: args{header: []byte("feat!: add user sorting option")},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Subject: "add user sorting option",
|
|
IsBreaking: true,
|
|
},
|
|
},
|
|
{
|
|
name: "type, scope and breaking",
|
|
args: args{header: []byte("feat(user)!: add user sorting option")},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user",
|
|
Subject: "add user sorting option",
|
|
IsBreaking: true,
|
|
},
|
|
},
|
|
{
|
|
name: "type with underscore (_)",
|
|
args: args{header: []byte("int_feat: add user sorting option")},
|
|
want: &Commit{
|
|
Type: "int_feat",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "type with hyphen (-)",
|
|
args: args{header: []byte("int-feat: add user sorting option")},
|
|
want: &Commit{
|
|
Type: "int-feat",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "scope with underscopre (_)",
|
|
args: args{
|
|
header: []byte("feat(user_sort): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user_sort",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "scope with hyphen (-)",
|
|
args: args{
|
|
header: []byte("feat(user-sort): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user-sort",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "scope with slash (/)",
|
|
args: args{
|
|
header: []byte("feat(user/sort): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user/sort",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "scope with period (.)",
|
|
args: args{
|
|
header: []byte("feat(user.sort): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user.sort",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "scope with dollar sign ($)",
|
|
args: args{
|
|
header: []byte("feat($user): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "$user",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "scope with star (*)",
|
|
args: args{
|
|
header: []byte("feat(user*): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user*",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "scope with space ( )",
|
|
args: args{
|
|
header: []byte("feat(user sort): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user sort",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "excess whitespace in type with scope",
|
|
args: args{
|
|
header: []byte(" feat (user sort): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user sort",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "excess whitespace in scope",
|
|
args: args{
|
|
header: []byte("feat( user sort ): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user sort",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "excess whitespace in subject",
|
|
args: args{
|
|
header: []byte("feat(user): add user sorting option "),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "empty scope",
|
|
args: args{
|
|
header: []byte("feat(): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Subject: "add user sorting option",
|
|
},
|
|
},
|
|
{
|
|
name: "multi-line header (LF)",
|
|
args: args{
|
|
header: []byte("feat(user)!: add user sorting\nnoption"),
|
|
},
|
|
want: &Commit{},
|
|
errStr: "invalid format: header has multiple lines",
|
|
errIs: []error{ErrFormat, ErrMultiLineHeader},
|
|
},
|
|
{
|
|
name: "multi-line header (CR)",
|
|
args: args{
|
|
header: []byte("feat(user)!: add user sorting\roption"),
|
|
},
|
|
want: &Commit{},
|
|
errStr: "invalid format: header has multiple lines",
|
|
errIs: []error{Err, ErrFormat, ErrMultiLineHeader},
|
|
},
|
|
{
|
|
name: "invalid type character",
|
|
args: args{
|
|
header: []byte("feat/internal: add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat/internal",
|
|
Subject: "add user sorting option",
|
|
},
|
|
errStr: `type must match: ^[\w-]+$`,
|
|
errIs: []error{Err, ErrType, ErrTypeFormat},
|
|
},
|
|
{
|
|
name: "invalid type character with scope",
|
|
args: args{
|
|
header: []byte("feat/internal(user): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat/internal",
|
|
Scope: "user",
|
|
Subject: "add user sorting option",
|
|
},
|
|
errStr: `type must match: ^[\w-]+$`,
|
|
errIs: []error{Err, ErrType, ErrTypeFormat},
|
|
},
|
|
{
|
|
name: "invalid scope character",
|
|
args: args{
|
|
header: []byte("feat(user#sort): add user sorting option"),
|
|
},
|
|
want: &Commit{
|
|
Type: "feat",
|
|
Scope: "user#sort",
|
|
Subject: "add user sorting option",
|
|
},
|
|
errStr: `scope must match: ^[\w\$\.\/\-\* ]+$`,
|
|
errIs: []error{Err, ErrScope, ErrScopeFormat},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := parseHeader(tt.args.header)
|
|
|
|
if tt.errStr != "" {
|
|
assert.EqualError(t, err, tt.errStr)
|
|
}
|
|
|
|
if len(tt.errIs) > 0 {
|
|
for _, errIs := range tt.errIs {
|
|
assert.True(t, errors.Is(err, errIs))
|
|
}
|
|
}
|
|
|
|
if len(tt.errIs) == 0 && tt.errStr == "" {
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
assert.Equal(t, tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_footers(t *testing.T) {
|
|
type args struct {
|
|
paragraph []byte
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []*rawFooter
|
|
}{
|
|
{
|
|
name: "without footer",
|
|
args: args{[]byte("this is not a fooder")},
|
|
want: []*rawFooter{},
|
|
},
|
|
{
|
|
name: "token footer on second line",
|
|
args: args{[]byte("this is not a fooder\nDone-By: John")},
|
|
want: []*rawFooter{},
|
|
},
|
|
{
|
|
name: "ticket footer on second line",
|
|
args: args{[]byte("this is not a fooder\nFixes #42")},
|
|
want: []*rawFooter{},
|
|
},
|
|
{
|
|
name: "breaking change footer on second line",
|
|
args: args{[]byte("this is not a fooder\nBREAKING CHANGE: Oops")},
|
|
want: []*rawFooter{},
|
|
},
|
|
{
|
|
name: "token footer",
|
|
args: args{[]byte("Reviewed-By: John Smith")},
|
|
want: []*rawFooter{
|
|
{Name: []byte("Reviewed-By"), Body: []byte("John Smith")},
|
|
},
|
|
},
|
|
{
|
|
name: "breaking change footer",
|
|
args: args{[]byte("BREAKING CHANGE: Oopsy")},
|
|
want: []*rawFooter{
|
|
{Name: []byte("BREAKING CHANGE"), Body: []byte("Oopsy")},
|
|
},
|
|
},
|
|
{
|
|
name: "ticket footer",
|
|
args: args{[]byte("Fixes #82")},
|
|
want: []*rawFooter{
|
|
{Name: []byte("Fixes"), Body: []byte("#82"), Ref: true},
|
|
},
|
|
},
|
|
{
|
|
name: "multiple token footers",
|
|
args: args{[]byte(
|
|
"Reviewed-By: John\n" +
|
|
"Committer: Smith\n",
|
|
)},
|
|
want: []*rawFooter{
|
|
{Name: []byte("Reviewed-By"), Body: []byte("John")},
|
|
{Name: []byte("Committer"), Body: []byte("Smith")},
|
|
},
|
|
},
|
|
{
|
|
name: "multiple ticket footers",
|
|
args: args{[]byte("Fixes #82\nFixes #74")},
|
|
want: []*rawFooter{
|
|
{Name: []byte("Fixes"), Body: []byte("#82"), Ref: true},
|
|
{Name: []byte("Fixes"), Body: []byte("#74"), Ref: true},
|
|
},
|
|
},
|
|
{
|
|
name: "multiple breaking change footers",
|
|
args: args{[]byte(
|
|
"BREAKING CHANGE: Oopsy\n" +
|
|
"BREAKING CHANGE: Again!",
|
|
)},
|
|
want: []*rawFooter{
|
|
{Name: []byte("BREAKING CHANGE"), Body: []byte("Oopsy")},
|
|
{Name: []byte("BREAKING CHANGE"), Body: []byte("Again!")},
|
|
},
|
|
},
|
|
{
|
|
name: "mixture of footer types",
|
|
args: args{[]byte(
|
|
"Fixes #930\n" +
|
|
"BREAKING CHANGE: Careful!\n" +
|
|
"Reviewed-By: Maria\n",
|
|
)},
|
|
want: []*rawFooter{
|
|
{Name: []byte("Fixes"), Body: []byte("#930"), Ref: true},
|
|
{Name: []byte("BREAKING CHANGE"), Body: []byte("Careful!")},
|
|
{Name: []byte("Reviewed-By"), Body: []byte("Maria")},
|
|
},
|
|
},
|
|
{
|
|
name: "multi-line footers",
|
|
args: args{[]byte(
|
|
"Description: Lorem ipsum dolor sit amet, consectetur\n" +
|
|
"adipiscing elit.Praesent eleifend lorem non purus\n" +
|
|
"finibus, interdum hendrerit sem bibendum.\n" +
|
|
"Fixes #94\n" +
|
|
"Misc-Other: Etiam porttitor mollis nulla, egestas\n" +
|
|
"facilisis nisi molestie ut. Quisque mi mi, commodo\n" +
|
|
"ut mattis a, scelerisque eu elit.\n" +
|
|
"BREAKING CHANGE: Duis id nulla eget velit maximus\n" +
|
|
"varius et egestas sem. Ut mi risus, pretium quis\n" +
|
|
"cursus quis, porttitor in ipsum.\n",
|
|
)},
|
|
want: []*rawFooter{
|
|
{
|
|
Name: []byte("Description"),
|
|
Body: []byte("Lorem ipsum dolor sit amet, consectetur\n" +
|
|
"adipiscing elit.Praesent eleifend lorem non purus\n" +
|
|
"finibus, interdum hendrerit sem bibendum."),
|
|
},
|
|
{Name: []byte("Fixes"), Body: []byte("#94"), Ref: true},
|
|
{
|
|
Name: []byte("Misc-Other"),
|
|
Body: []byte("Etiam porttitor mollis nulla, egestas\n" +
|
|
"facilisis nisi molestie ut. Quisque mi mi, commodo\n" +
|
|
"ut mattis a, scelerisque eu elit."),
|
|
},
|
|
{
|
|
Name: []byte("BREAKING CHANGE"),
|
|
Body: []byte("Duis id nulla eget velit maximus\n" +
|
|
"varius et egestas sem. Ut mi risus, pretium quis\n" +
|
|
"cursus quis, porttitor in ipsum."),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := footers(tt.args.paragraph)
|
|
|
|
assert.Equal(t, tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_paragraph(t *testing.T) {
|
|
type args struct {
|
|
input []byte
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want [][]byte
|
|
}{
|
|
{
|
|
name: "single line string",
|
|
args: args{input: []byte("hello world\n")},
|
|
want: [][]byte{[]byte("hello world")},
|
|
},
|
|
{
|
|
name: "multi-line line string",
|
|
args: args{input: []byte("hello world\nthe brown fox\n")},
|
|
want: [][]byte{[]byte("hello world\nthe brown fox")},
|
|
},
|
|
{
|
|
name: "excess whitespace",
|
|
args: args{input: []byte(" \n hello world\nthe brown fox \n ")},
|
|
want: [][]byte{[]byte("hello world\nthe brown fox")},
|
|
},
|
|
{
|
|
name: "multiple paragraphs",
|
|
args: args{input: []byte(
|
|
"Lorem ipsum dolor sit amet, consectetur adipiscing\n" +
|
|
"elit.Praesent eleifend lorem non purus finibus,\n" +
|
|
"interdum hendrerit sem bibendum.\n" +
|
|
"\n" +
|
|
"Etiam porttitor mollis nulla, egestas facilisis nisi\n" +
|
|
"molestie ut. Quisque mi mi, commodo ut mattis a,\n" +
|
|
"scelerisque eu elit.\n" +
|
|
"\n" +
|
|
"Duis id nulla eget velit maximus varius et egestas\n" +
|
|
"sem. Ut mi risus, pretium quis cursus quis,\n" +
|
|
"porttitor in ipsum.\n",
|
|
)},
|
|
want: [][]byte{
|
|
[]byte(
|
|
"Lorem ipsum dolor sit amet, consectetur adipiscing\n" +
|
|
"elit.Praesent eleifend lorem non purus finibus,\n" +
|
|
"interdum hendrerit sem bibendum.",
|
|
),
|
|
[]byte(
|
|
"Etiam porttitor mollis nulla, egestas facilisis nisi\n" +
|
|
"molestie ut. Quisque mi mi, commodo ut mattis a,\n" +
|
|
"scelerisque eu elit.",
|
|
),
|
|
[]byte(
|
|
"Duis id nulla eget velit maximus varius et egestas\n" +
|
|
"sem. Ut mi risus, pretium quis cursus quis,\n" +
|
|
"porttitor in ipsum.",
|
|
),
|
|
},
|
|
},
|
|
{
|
|
name: "paragraphs with surrounding whitespace",
|
|
args: args{input: []byte(
|
|
"\n" +
|
|
" \n" +
|
|
" Lorem ipsum dolor sit amet, consectetur adipiscing\n" +
|
|
"elit.Praesent eleifend lorem non purus finibus,\n" +
|
|
"interdum hendrerit sem bibendum. \n" +
|
|
"\n" +
|
|
"\n" +
|
|
" Etiam porttitor mollis nulla, egestas facilisis nisi\n" +
|
|
"molestie ut. Quisque mi mi, commodo ut mattis a,\n" +
|
|
"scelerisque eu elit.\n" +
|
|
" \n" +
|
|
" ",
|
|
)},
|
|
want: [][]byte{
|
|
[]byte(
|
|
"Lorem ipsum dolor sit amet, consectetur adipiscing\n" +
|
|
"elit.Praesent eleifend lorem non purus finibus,\n" +
|
|
"interdum hendrerit sem bibendum.",
|
|
),
|
|
[]byte(
|
|
"Etiam porttitor mollis nulla, egestas facilisis nisi\n" +
|
|
"molestie ut. Quisque mi mi, commodo ut mattis a,\n" +
|
|
"scelerisque eu elit.",
|
|
),
|
|
},
|
|
},
|
|
{
|
|
name: "CRLF line separator",
|
|
args: args{input: []byte(
|
|
"Lorem ipsum dolor sit amet, consectetur adipiscing\r\n" +
|
|
"elit.Praesent eleifend lorem non purus finibus,\r\n" +
|
|
"interdum hendrerit sem bibendum.\r\n" +
|
|
"\r\n" +
|
|
"Etiam porttitor mollis nulla, egestas facilisis nisi\r\n" +
|
|
"molestie ut. Quisque mi mi, commodo ut mattis a,\r\n" +
|
|
"scelerisque eu elit.\r\n",
|
|
)},
|
|
want: [][]byte{
|
|
[]byte(
|
|
"Lorem ipsum dolor sit amet, consectetur adipiscing\n" +
|
|
"elit.Praesent eleifend lorem non purus finibus,\n" +
|
|
"interdum hendrerit sem bibendum.",
|
|
),
|
|
[]byte(
|
|
"Etiam porttitor mollis nulla, egestas facilisis nisi\n" +
|
|
"molestie ut. Quisque mi mi, commodo ut mattis a,\n" +
|
|
"scelerisque eu elit.",
|
|
),
|
|
},
|
|
},
|
|
{
|
|
name: "CR line separator",
|
|
args: args{input: []byte(
|
|
"Lorem ipsum dolor sit amet, consectetur adipiscing\r" +
|
|
"elit.Praesent eleifend lorem non purus finibus,\r" +
|
|
"interdum hendrerit sem bibendum.\r" +
|
|
"\r" +
|
|
"Etiam porttitor mollis nulla, egestas facilisis nisi\r" +
|
|
"molestie ut. Quisque mi mi, commodo ut mattis a,\r" +
|
|
"scelerisque eu elit.\r",
|
|
)},
|
|
want: [][]byte{
|
|
[]byte(
|
|
"Lorem ipsum dolor sit amet, consectetur adipiscing\n" +
|
|
"elit.Praesent eleifend lorem non purus finibus,\n" +
|
|
"interdum hendrerit sem bibendum.",
|
|
),
|
|
[]byte(
|
|
"Etiam porttitor mollis nulla, egestas facilisis nisi\n" +
|
|
"molestie ut. Quisque mi mi, commodo ut mattis a,\n" +
|
|
"scelerisque eu elit.",
|
|
),
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := paragraphs(tt.args.input)
|
|
|
|
assert.Equal(t, tt.want, got)
|
|
})
|
|
}
|
|
}
|