Files
go-conventionalcommit/line_test.go

991 lines
17 KiB
Go

package conventionalcommit
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestLine_Empty(t *testing.T) {
tests := []struct {
name string
line *Line
want bool
}{
{
name: "nil",
line: &Line{},
want: true,
},
{
name: "empty",
line: &Line{
Number: 1,
Content: []byte(""),
Break: []byte{},
},
want: true,
},
{
name: "space only",
line: &Line{
Number: 1,
Content: []byte(" "),
Break: []byte{},
},
want: false,
},
{
name: "tab only",
line: &Line{
Number: 1,
Content: []byte("\t\t"),
Break: []byte{},
},
want: false,
},
{
name: "spaces and tabs",
line: &Line{
Number: 1,
Content: []byte(" \t "),
Break: []byte{},
},
want: false,
},
{
name: "text",
line: &Line{
Number: 1,
Content: []byte("foobar"),
Break: []byte{},
},
want: false,
},
{
name: "text with surrounding white space",
line: &Line{
Number: 1,
Content: []byte(" foobar "),
Break: []byte{},
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.line.Empty()
assert.Equal(t, tt.want, got)
})
}
}
func TestLine_Blank(t *testing.T) {
tests := []struct {
name string
line *Line
want bool
}{
{
name: "nil",
line: &Line{},
want: true,
},
{
name: "empty",
line: &Line{
Number: 1,
Content: []byte(""),
Break: []byte{},
},
want: true,
},
{
name: "space only",
line: &Line{
Number: 1,
Content: []byte(" "),
Break: []byte{},
},
want: true,
},
{
name: "tab only",
line: &Line{
Number: 1,
Content: []byte("\t\t"),
Break: []byte{},
},
want: true,
},
{
name: "spaces and tabs",
line: &Line{
Number: 1,
Content: []byte(" \t "),
Break: []byte{},
},
want: true,
},
{
name: "text",
line: &Line{
Number: 1,
Content: []byte("foobar"),
Break: []byte{},
},
want: false,
},
{
name: "text with surrounding white space",
line: &Line{
Number: 1,
Content: []byte(" foobar "),
Break: []byte{},
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.line.Blank()
assert.Equal(t, tt.want, got)
})
}
}
func TestLine_Comment(t *testing.T) {
tests := []struct {
name string
line *Line
want bool
}{
{
name: "nil",
line: &Line{},
want: false,
},
{
name: "empty",
line: &Line{
Number: 1,
Content: []byte(""),
Break: []byte{},
},
want: false,
},
{
name: "space only",
line: &Line{
Number: 1,
Content: []byte(" "),
Break: []byte{},
},
want: false,
},
{
name: "tab only",
line: &Line{
Number: 1,
Content: []byte("\t\t"),
Break: []byte{},
},
want: false,
},
{
name: "spaces and tabs",
line: &Line{
Number: 1,
Content: []byte(" \t "),
Break: []byte{},
},
want: false,
},
{
name: "text",
line: &Line{
Number: 1,
Content: []byte("foobar"),
Break: []byte{},
},
want: false,
},
{
name: "beings with hash",
line: &Line{
Number: 1,
Content: []byte("# foo bar"),
Break: []byte{},
},
want: true,
},
{
name: "beings with hash after whitespace",
line: &Line{
Number: 1,
Content: []byte(" \t # foo bar"),
Break: []byte{},
},
want: true,
},
{
name: "has hash in middle of text",
line: &Line{
Number: 1,
Content: []byte(" foo # bar"),
Break: []byte{},
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.line.Comment()
assert.Equal(t, tt.want, got)
})
}
}
func TestNewLines(t *testing.T) {
tests := []struct {
name string
content []byte
want Lines
}{
{
name: "nil",
content: nil,
want: Lines{},
},
{
name: "empty",
content: []byte{},
want: Lines{},
},
{
name: "single line without trailing linebreak",
content: []byte("hello world"),
want: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte{},
},
},
},
{
name: "single line with trailing LF",
content: []byte("hello world\n"),
want: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\n"),
},
{
Number: 2,
Content: []byte(""),
Break: []byte{},
},
},
},
{
name: "single line with trailing CRLF",
content: []byte("hello world\r\n"),
want: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\r\n"),
},
{
Number: 2,
Content: []byte(""),
Break: []byte{},
},
},
},
{
name: "single line with trailing CR",
content: []byte("hello world\r"),
want: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\r"),
},
{
Number: 2,
Content: []byte(""),
Break: []byte{},
},
},
},
{
name: "multiple lines separated by LF",
content: []byte("hello world\nfoo\nbar"),
want: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\n"),
},
{
Number: 2,
Content: []byte("foo"),
Break: []byte("\n"),
},
{
Number: 3,
Content: []byte("bar"),
Break: []byte{},
},
},
},
{
name: "multiple lines separated by LF with trailing LF",
content: []byte("hello world\nfoo\nbar\n"),
want: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\n"),
},
{
Number: 2,
Content: []byte("foo"),
Break: []byte("\n"),
},
{
Number: 3,
Content: []byte("bar"),
Break: []byte("\n"),
},
{
Number: 4,
Content: []byte(""),
Break: []byte{},
},
},
},
{
name: "multiple lines separated by CRLF",
content: []byte("hello world\r\nfoo\r\nbar"),
want: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\r\n"),
},
{
Number: 2,
Content: []byte("foo"),
Break: []byte("\r\n"),
},
{
Number: 3,
Content: []byte("bar"),
Break: []byte{},
},
},
},
{
name: "multiple lines separated by CRLF with trailing CRLF",
content: []byte("hello world\r\nfoo\r\nbar\r\n"),
want: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\r\n"),
},
{
Number: 2,
Content: []byte("foo"),
Break: []byte("\r\n"),
},
{
Number: 3,
Content: []byte("bar"),
Break: []byte("\r\n"),
},
{
Number: 4,
Content: []byte(""),
Break: []byte{},
},
},
},
{
name: "multiple lines separated by CR",
content: []byte("hello world\rfoo\rbar"),
want: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\r"),
},
{
Number: 2,
Content: []byte("foo"),
Break: []byte("\r"),
},
{
Number: 3,
Content: []byte("bar"),
Break: []byte{},
},
},
},
{
name: "multiple lines separated by CR with trailing CR",
content: []byte("hello world\rfoo\rbar\r"),
want: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\r"),
},
{
Number: 2,
Content: []byte("foo"),
Break: []byte("\r"),
},
{
Number: 3,
Content: []byte("bar"),
Break: []byte("\r"),
},
{
Number: 4,
Content: []byte(""),
Break: []byte{},
},
},
},
{
name: "multiple lines separated by mixed break types",
content: []byte("hello\nworld\r\nfoo\rbar"),
want: Lines{
{
Number: 1,
Content: []byte("hello"),
Break: []byte("\n"),
},
{
Number: 2,
Content: []byte("world"),
Break: []byte("\r\n"),
},
{
Number: 3,
Content: []byte("foo"),
Break: []byte("\r"),
},
{
Number: 4,
Content: []byte("bar"),
Break: []byte{},
},
},
},
{
name: "multiple lines separated by mixed break types with " +
"trailing LF",
content: []byte("hello\nworld\r\nfoo\rbar\n"),
want: Lines{
{
Number: 1,
Content: []byte("hello"),
Break: []byte("\n"),
},
{
Number: 2,
Content: []byte("world"),
Break: []byte("\r\n"),
},
{
Number: 3,
Content: []byte("foo"),
Break: []byte("\r"),
},
{
Number: 4,
Content: []byte("bar"),
Break: []byte("\n"),
},
{
Number: 5,
Content: []byte(""),
Break: []byte{},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := NewLines(tt.content)
assert.Equal(t, tt.want, got)
})
}
}
var linesTestCases = []struct {
name string
lines Lines
bytes []byte
firstTextIndex int
lastTextIndex int
}{
{
name: "no lines",
lines: Lines{},
bytes: []byte(""),
firstTextIndex: -1,
lastTextIndex: -1,
},
{
name: "empty line",
lines: Lines{
{
Number: 1,
Content: []byte(""),
},
},
bytes: []byte(""),
firstTextIndex: -1,
lastTextIndex: -1,
},
{
name: "whitespace line",
lines: Lines{
{
Number: 1,
Content: []byte(" "),
},
},
bytes: []byte(" "),
firstTextIndex: -1,
lastTextIndex: -1,
},
{
name: "multiple whitespace lines",
lines: Lines{
{
Number: 1,
Content: []byte(" "),
Break: []byte("\n"),
},
{
Number: 2,
Content: []byte("\t"),
Break: []byte("\n"),
},
{
Number: 3,
Content: []byte(" "),
Break: []byte{},
},
},
bytes: []byte(" \n\t\n "),
firstTextIndex: -1,
lastTextIndex: -1,
},
{
name: "single line",
lines: Lines{
{
Number: 1,
Content: []byte("hello world"),
},
},
bytes: []byte("hello world"),
firstTextIndex: 0,
lastTextIndex: 0,
},
{
name: "single line with trailing LF",
lines: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\n"),
},
{
Number: 2,
Content: []byte(""),
Break: []byte{},
},
},
bytes: []byte("hello world\n"),
firstTextIndex: 0,
lastTextIndex: 0,
},
{
name: "single line with trailing CRLF",
lines: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\r\n"),
},
{
Number: 2,
Content: []byte(""),
Break: []byte{},
},
},
bytes: []byte("hello world\r\n"),
firstTextIndex: 0,
lastTextIndex: 0,
},
{
name: "single line with trailing CR",
lines: Lines{
{
Number: 1,
Content: []byte("hello world"),
Break: []byte("\r"),
},
{
Number: 2,
Content: []byte(""),
Break: []byte{},
},
},
bytes: []byte("hello world\r"),
firstTextIndex: 0,
lastTextIndex: 0,
},
{
name: "multi-line separated by LF",
lines: Lines{
{
Number: 1,
Content: []byte(""),
Break: []byte("\n"),
},
{
Number: 2,
Content: []byte("Aliquam feugiat tellus ut neque."),
Break: []byte("\n"),
},
{
Number: 3,
Content: []byte("Sed bibendum."),
Break: []byte("\n"),
},
{
Number: 4,
Content: []byte("Nullam libero mauris, consequat."),
Break: []byte("\n"),
},
{
Number: 5,
Content: []byte(""),
Break: []byte("\n"),
},
{
Number: 6,
Content: []byte("Integer placerat tristique nisl."),
Break: []byte("\n"),
},
{
Number: 7,
Content: []byte("Etiam vel neque nec dui bibendum."),
Break: []byte("\n"),
},
{
Number: 8,
Content: []byte(""),
Break: []byte("\n"),
},
{
Number: 9,
Content: []byte(""),
Break: []byte("\n"),
},
{
Number: 10,
Content: []byte("Nullam libero mauris, dictum id, arcu."),
Break: []byte("\n"),
},
{
Number: 11,
Content: []byte(""),
Break: []byte{},
},
},
bytes: []byte(
"\n" +
"Aliquam feugiat tellus ut neque.\n" +
"Sed bibendum.\n" +
"Nullam libero mauris, consequat.\n" +
"\n" +
"Integer placerat tristique nisl.\n" +
"Etiam vel neque nec dui bibendum.\n" +
"\n" +
"\n" +
"Nullam libero mauris, dictum id, arcu.\n",
),
firstTextIndex: 1,
lastTextIndex: 9,
},
{
name: "multi-line separated by CRLF",
lines: Lines{
{
Number: 1,
Content: []byte(""),
Break: []byte("\r\n"),
},
{
Number: 2,
Content: []byte("Aliquam feugiat tellus ut neque."),
Break: []byte("\r\n"),
},
{
Number: 3,
Content: []byte("Sed bibendum."),
Break: []byte("\r\n"),
},
{
Number: 4,
Content: []byte("Nullam libero mauris, consequat."),
Break: []byte("\r\n"),
},
{
Number: 5,
Content: []byte(""),
Break: []byte("\r\n"),
},
{
Number: 6,
Content: []byte("Integer placerat tristique nisl."),
Break: []byte("\r\n"),
},
{
Number: 7,
Content: []byte("Etiam vel neque nec dui bibendum."),
Break: []byte("\r\n"),
},
{
Number: 8,
Content: []byte(""),
Break: []byte("\r\n"),
},
{
Number: 9,
Content: []byte(""),
Break: []byte("\r\n"),
},
{
Number: 10,
Content: []byte("Nullam libero mauris, dictum id, arcu."),
Break: []byte("\r\n"),
},
{
Number: 11,
Content: []byte(""),
Break: []byte{},
},
},
bytes: []byte(
"\r\n" +
"Aliquam feugiat tellus ut neque.\r\n" +
"Sed bibendum.\r\n" +
"Nullam libero mauris, consequat.\r\n" +
"\r\n" +
"Integer placerat tristique nisl.\r\n" +
"Etiam vel neque nec dui bibendum.\r\n" +
"\r\n" +
"\r\n" +
"Nullam libero mauris, dictum id, arcu.\r\n",
),
firstTextIndex: 1,
lastTextIndex: 9,
},
{
name: "multi-line separated by CR",
lines: Lines{
{
Number: 1,
Content: []byte(""),
Break: []byte("\r"),
},
{
Number: 2,
Content: []byte("Aliquam feugiat tellus ut neque."),
Break: []byte("\r"),
},
{
Number: 3,
Content: []byte("Sed bibendum."),
Break: []byte("\r"),
},
{
Number: 4,
Content: []byte("Nullam libero mauris, consequat."),
Break: []byte("\r"),
},
{
Number: 5,
Content: []byte(""),
Break: []byte("\r"),
},
{
Number: 6,
Content: []byte("Integer placerat tristique nisl."),
Break: []byte("\r"),
},
{
Number: 7,
Content: []byte("Etiam vel neque nec dui bibendum."),
Break: []byte("\r"),
},
{
Number: 8,
Content: []byte(""),
Break: []byte("\r"),
},
{
Number: 9,
Content: []byte(""),
Break: []byte("\r"),
},
{
Number: 10,
Content: []byte("Nullam libero mauris, dictum id, arcu."),
Break: []byte("\r"),
},
{
Number: 11,
Content: []byte(""),
Break: []byte{},
},
},
bytes: []byte(
"\r" +
"Aliquam feugiat tellus ut neque.\r" +
"Sed bibendum.\r" +
"Nullam libero mauris, consequat.\r" +
"\r" +
"Integer placerat tristique nisl.\r" +
"Etiam vel neque nec dui bibendum.\r" +
"\r" +
"\r" +
"Nullam libero mauris, dictum id, arcu.\r",
),
firstTextIndex: 1,
lastTextIndex: 9,
},
}
func TestLines_FirstTextIndex(t *testing.T) {
for _, tt := range linesTestCases {
t.Run(tt.name, func(t *testing.T) {
got := tt.lines.FirstTextIndex()
assert.Equal(t, tt.firstTextIndex, got)
})
}
}
func BenchmarkLines_FirstTextIndex(b *testing.B) {
for _, tt := range linesTestCases {
b.Run(tt.name, func(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = tt.lines.FirstTextIndex()
}
})
}
}
func TestLines_LastTextIndex(t *testing.T) {
for _, tt := range linesTestCases {
t.Run(tt.name, func(t *testing.T) {
got := tt.lines.LastTextIndex()
assert.Equal(t, tt.lastTextIndex, got)
})
}
}
func BenchmarkLines_LastTextIndex(b *testing.B) {
for _, tt := range linesTestCases {
b.Run(tt.name, func(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = tt.lines.LastTextIndex()
}
})
}
}
func TestLines_Trim(t *testing.T) {
for _, tt := range linesTestCases {
t.Run(tt.name, func(t *testing.T) {
want := Lines{}
if tt.firstTextIndex != -1 {
want = tt.lines[tt.firstTextIndex : tt.lastTextIndex+1]
}
got := tt.lines.Trim()
assert.Equal(t, want, got)
})
}
}
func BenchmarkLines_Trim(b *testing.B) {
for _, tt := range linesTestCases {
b.Run(tt.name, func(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = tt.lines.Trim()
}
})
}
}
func TestLines_Bytes(t *testing.T) {
for _, tt := range linesTestCases {
t.Run(tt.name, func(t *testing.T) {
got := tt.lines.Bytes()
assert.Equal(t, tt.bytes, got)
})
}
}
func BenchmarkLines_Bytes(b *testing.B) {
for _, tt := range linesTestCases {
b.Run(tt.name, func(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = tt.lines.Bytes()
}
})
}
}
func TestLines_String(t *testing.T) {
for _, tt := range linesTestCases {
t.Run(tt.name, func(t *testing.T) {
got := tt.lines.String()
assert.Equal(t, string(tt.bytes), got)
})
}
}
func BenchmarkLines_String(b *testing.B) {
for _, tt := range linesTestCases {
b.Run(tt.name, func(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = tt.lines.String()
}
})
}
}