This commit completely removes the iostreams.NewColorScheme() initializer function in favor of exporting the type fields for greater clarity in its use. The result being code specifying only the fields that matter to test cases.
713 lines
18 KiB
Go
713 lines
18 KiB
Go
package list
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"net/http"
|
|
"regexp"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/MakeNowJust/heredoc"
|
|
"github.com/cli/cli/v2/internal/config"
|
|
"github.com/cli/cli/v2/internal/gh"
|
|
"github.com/cli/cli/v2/pkg/cmdutil"
|
|
"github.com/cli/cli/v2/pkg/httpmock"
|
|
"github.com/cli/cli/v2/pkg/iostreams"
|
|
"github.com/google/shlex"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestNewCmdList(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
cli string
|
|
wants ListOptions
|
|
wantsErr bool
|
|
}{
|
|
{
|
|
name: "no arguments",
|
|
wants: ListOptions{
|
|
Limit: 10,
|
|
Visibility: "all",
|
|
},
|
|
},
|
|
{
|
|
name: "public",
|
|
cli: "--public",
|
|
wants: ListOptions{
|
|
Limit: 10,
|
|
Visibility: "public",
|
|
},
|
|
},
|
|
{
|
|
name: "secret",
|
|
cli: "--secret",
|
|
wants: ListOptions{
|
|
Limit: 10,
|
|
Visibility: "secret",
|
|
},
|
|
},
|
|
{
|
|
name: "secret with explicit false value",
|
|
cli: "--secret=false",
|
|
wants: ListOptions{
|
|
Limit: 10,
|
|
Visibility: "all",
|
|
},
|
|
},
|
|
{
|
|
name: "public and secret",
|
|
cli: "--secret --public",
|
|
wants: ListOptions{
|
|
Limit: 10,
|
|
Visibility: "secret",
|
|
},
|
|
},
|
|
{
|
|
name: "limit",
|
|
cli: "--limit 30",
|
|
wants: ListOptions{
|
|
Limit: 30,
|
|
Visibility: "all",
|
|
},
|
|
},
|
|
{
|
|
name: "invalid limit",
|
|
cli: "--limit 0",
|
|
wantsErr: true,
|
|
},
|
|
{
|
|
name: "filter and include-content",
|
|
cli: "--filter octo --include-content",
|
|
wants: ListOptions{
|
|
Limit: 10,
|
|
Filter: regexp.MustCompilePOSIX("octo"),
|
|
IncludeContent: true,
|
|
Visibility: "all",
|
|
},
|
|
},
|
|
{
|
|
name: "invalid filter",
|
|
cli: "--filter octo(",
|
|
wantsErr: true,
|
|
},
|
|
{
|
|
name: "include content without filter",
|
|
cli: "--include-content",
|
|
wantsErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
f := &cmdutil.Factory{}
|
|
|
|
argv, err := shlex.Split(tt.cli)
|
|
assert.NoError(t, err)
|
|
|
|
var gotOpts *ListOptions
|
|
cmd := NewCmdList(f, func(opts *ListOptions) error {
|
|
gotOpts = opts
|
|
return nil
|
|
})
|
|
cmd.SetArgs(argv)
|
|
cmd.SetIn(&bytes.Buffer{})
|
|
cmd.SetOut(&bytes.Buffer{})
|
|
cmd.SetErr(&bytes.Buffer{})
|
|
|
|
_, err = cmd.ExecuteC()
|
|
if tt.wantsErr {
|
|
assert.Error(t, err)
|
|
return
|
|
}
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, tt.wants.Visibility, gotOpts.Visibility)
|
|
assert.Equal(t, tt.wants.Limit, gotOpts.Limit)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_listRun(t *testing.T) {
|
|
const query = `query GistList\b`
|
|
sixHours, _ := time.ParseDuration("6h")
|
|
sixHoursAgo := time.Now().Add(-sixHours)
|
|
absTime, _ := time.Parse(time.RFC3339, "2020-07-30T15:24:28Z")
|
|
|
|
tests := []struct {
|
|
name string
|
|
opts *ListOptions
|
|
wantErr bool
|
|
wantOut string
|
|
stubs func(*httpmock.Registry)
|
|
color bool
|
|
nontty bool
|
|
}{
|
|
{
|
|
name: "no gists",
|
|
opts: &ListOptions{},
|
|
stubs: func(reg *httpmock.Registry) {
|
|
reg.Register(
|
|
httpmock.GraphQL(query),
|
|
httpmock.StringResponse(`{ "data": { "viewer": {
|
|
"gists": { "nodes": [] }
|
|
} } }`))
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "default behavior",
|
|
opts: &ListOptions{},
|
|
stubs: func(reg *httpmock.Registry) {
|
|
reg.Register(
|
|
httpmock.GraphQL(query),
|
|
httpmock.StringResponse(fmt.Sprintf(
|
|
`{ "data": { "viewer": { "gists": { "nodes": [
|
|
{
|
|
"name": "1234567890",
|
|
"files": [{ "name": "cool.txt" }],
|
|
"description": "",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
},
|
|
{
|
|
"name": "4567890123",
|
|
"files": [{ "name": "gistfile0.txt" }],
|
|
"description": "",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
},
|
|
{
|
|
"name": "2345678901",
|
|
"files": [
|
|
{ "name": "gistfile0.txt" },
|
|
{ "name": "gistfile1.txt" }
|
|
],
|
|
"description": "tea leaves thwart those who court catastrophe",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": false
|
|
},
|
|
{
|
|
"name": "3456789012",
|
|
"files": [
|
|
{ "name": "gistfile0.txt" },
|
|
{ "name": "gistfile1.txt" },
|
|
{ "name": "gistfile2.txt" },
|
|
{ "name": "gistfile3.txt" },
|
|
{ "name": "gistfile4.txt" },
|
|
{ "name": "gistfile5.txt" },
|
|
{ "name": "gistfile6.txt" },
|
|
{ "name": "gistfile7.txt" },
|
|
{ "name": "gistfile9.txt" },
|
|
{ "name": "gistfile10.txt" },
|
|
{ "name": "gistfile11.txt" }
|
|
],
|
|
"description": "short desc",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": false
|
|
}
|
|
] } } } }`,
|
|
sixHoursAgo.Format(time.RFC3339),
|
|
)),
|
|
)
|
|
},
|
|
wantOut: heredoc.Doc(`
|
|
ID DESCRIPTION FILES VISIBILITY UPDATED
|
|
1234567890 cool.txt 1 file public about 6 hours ago
|
|
4567890123 1 file public about 6 hours ago
|
|
2345678901 tea leaves thwart those ... 2 files secret about 6 hours ago
|
|
3456789012 short desc 11 files secret about 6 hours ago
|
|
`),
|
|
},
|
|
{
|
|
name: "with public filter",
|
|
opts: &ListOptions{Visibility: "public"},
|
|
stubs: func(reg *httpmock.Registry) {
|
|
reg.Register(
|
|
httpmock.GraphQL(query),
|
|
httpmock.StringResponse(fmt.Sprintf(
|
|
`{ "data": { "viewer": { "gists": { "nodes": [
|
|
{
|
|
"name": "1234567890",
|
|
"files": [{ "name": "cool.txt" }],
|
|
"description": "",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
},
|
|
{
|
|
"name": "4567890123",
|
|
"files": [{ "name": "gistfile0.txt" }],
|
|
"description": "",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
}
|
|
] } } } }`,
|
|
sixHoursAgo.Format(time.RFC3339),
|
|
)),
|
|
)
|
|
},
|
|
wantOut: heredoc.Doc(`
|
|
ID DESCRIPTION FILES VISIBILITY UPDATED
|
|
1234567890 cool.txt 1 file public about 6 hours ago
|
|
4567890123 1 file public about 6 hours ago
|
|
`),
|
|
},
|
|
{
|
|
name: "with secret filter",
|
|
opts: &ListOptions{Visibility: "secret"},
|
|
stubs: func(reg *httpmock.Registry) {
|
|
reg.Register(
|
|
httpmock.GraphQL(query),
|
|
httpmock.StringResponse(fmt.Sprintf(
|
|
`{ "data": { "viewer": { "gists": { "nodes": [
|
|
{
|
|
"name": "2345678901",
|
|
"files": [
|
|
{ "name": "gistfile0.txt" },
|
|
{ "name": "gistfile1.txt" }
|
|
],
|
|
"description": "tea leaves thwart those who court catastrophe",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": false
|
|
},
|
|
{
|
|
"name": "3456789012",
|
|
"files": [
|
|
{ "name": "gistfile0.txt" },
|
|
{ "name": "gistfile1.txt" },
|
|
{ "name": "gistfile2.txt" },
|
|
{ "name": "gistfile3.txt" },
|
|
{ "name": "gistfile4.txt" },
|
|
{ "name": "gistfile5.txt" },
|
|
{ "name": "gistfile6.txt" },
|
|
{ "name": "gistfile7.txt" },
|
|
{ "name": "gistfile9.txt" },
|
|
{ "name": "gistfile10.txt" },
|
|
{ "name": "gistfile11.txt" }
|
|
],
|
|
"description": "short desc",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": false
|
|
}
|
|
] } } } }`,
|
|
sixHoursAgo.Format(time.RFC3339),
|
|
)),
|
|
)
|
|
},
|
|
wantOut: heredoc.Doc(`
|
|
ID DESCRIPTION FILES VISIBILITY UPDATED
|
|
2345678901 tea leaves thwart those ... 2 files secret about 6 hours ago
|
|
3456789012 short desc 11 files secret about 6 hours ago
|
|
`),
|
|
},
|
|
{
|
|
name: "with limit",
|
|
opts: &ListOptions{Limit: 1},
|
|
stubs: func(reg *httpmock.Registry) {
|
|
reg.Register(
|
|
httpmock.GraphQL(query),
|
|
httpmock.StringResponse(fmt.Sprintf(
|
|
`{ "data": { "viewer": { "gists": { "nodes": [
|
|
{
|
|
"name": "1234567890",
|
|
"files": [{ "name": "cool.txt" }],
|
|
"description": "",
|
|
"updatedAt": "%v",
|
|
"isPublic": true
|
|
}
|
|
] } } } }`,
|
|
sixHoursAgo.Format(time.RFC3339),
|
|
)),
|
|
)
|
|
},
|
|
wantOut: heredoc.Doc(`
|
|
ID DESCRIPTION FILES VISIBILITY UPDATED
|
|
1234567890 cool.txt 1 file public about 6 hours ago
|
|
`),
|
|
},
|
|
{
|
|
name: "nontty output",
|
|
opts: &ListOptions{},
|
|
stubs: func(reg *httpmock.Registry) {
|
|
reg.Register(
|
|
httpmock.GraphQL(query),
|
|
httpmock.StringResponse(fmt.Sprintf(
|
|
`{ "data": { "viewer": { "gists": { "nodes": [
|
|
{
|
|
"name": "1234567890",
|
|
"files": [{ "name": "cool.txt" }],
|
|
"description": "",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
},
|
|
{
|
|
"name": "4567890123",
|
|
"files": [{ "name": "gistfile0.txt" }],
|
|
"description": "",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
},
|
|
{
|
|
"name": "2345678901",
|
|
"files": [
|
|
{ "name": "gistfile0.txt" },
|
|
{ "name": "gistfile1.txt" }
|
|
],
|
|
"description": "tea leaves thwart those who court catastrophe",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": false
|
|
},
|
|
{
|
|
"name": "3456789012",
|
|
"files": [
|
|
{ "name": "gistfile0.txt" },
|
|
{ "name": "gistfile1.txt" },
|
|
{ "name": "gistfile2.txt" },
|
|
{ "name": "gistfile3.txt" },
|
|
{ "name": "gistfile4.txt" },
|
|
{ "name": "gistfile5.txt" },
|
|
{ "name": "gistfile6.txt" },
|
|
{ "name": "gistfile7.txt" },
|
|
{ "name": "gistfile9.txt" },
|
|
{ "name": "gistfile10.txt" },
|
|
{ "name": "gistfile11.txt" }
|
|
],
|
|
"description": "short desc",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": false
|
|
}
|
|
] } } } }`,
|
|
absTime.Format(time.RFC3339),
|
|
)),
|
|
)
|
|
},
|
|
wantOut: heredoc.Doc(`
|
|
1234567890 cool.txt 1 file public 2020-07-30T15:24:28Z
|
|
4567890123 1 file public 2020-07-30T15:24:28Z
|
|
2345678901 tea leaves thwart those who court catastrophe 2 files secret 2020-07-30T15:24:28Z
|
|
3456789012 short desc 11 files secret 2020-07-30T15:24:28Z
|
|
`),
|
|
nontty: true,
|
|
},
|
|
{
|
|
name: "filtered",
|
|
opts: &ListOptions{
|
|
Filter: regexp.MustCompile("octo"),
|
|
Visibility: "all",
|
|
},
|
|
nontty: true,
|
|
stubs: func(reg *httpmock.Registry) {
|
|
reg.Register(
|
|
httpmock.GraphQL(query),
|
|
httpmock.StringResponse(fmt.Sprintf(
|
|
`{ "data": { "viewer": { "gists": { "nodes": [
|
|
{
|
|
"name": "1234",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "foo" }
|
|
],
|
|
"description": "octo match in the description",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
},
|
|
{
|
|
"name": "2345",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "foo" },
|
|
{ "name": "octo.txt", "text": "bar" }
|
|
],
|
|
"description": "match in the file name",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": false
|
|
},
|
|
{
|
|
"name": "3456",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "octo in the text" }
|
|
],
|
|
"description": "match in the file text",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
}
|
|
] } } } }`,
|
|
absTime.Format(time.RFC3339),
|
|
)),
|
|
)
|
|
},
|
|
wantOut: heredoc.Docf(`
|
|
1234%[1]socto match in the description%[1]s1 file%[1]spublic%[1]s2020-07-30T15:24:28Z
|
|
2345%[1]smatch in the file name%[1]s2 files%[1]ssecret%[1]s2020-07-30T15:24:28Z
|
|
`, "\t"),
|
|
},
|
|
{
|
|
name: "filtered (tty)",
|
|
opts: &ListOptions{
|
|
Filter: regexp.MustCompile("octo"),
|
|
Visibility: "all",
|
|
},
|
|
color: true,
|
|
stubs: func(reg *httpmock.Registry) {
|
|
reg.Register(
|
|
httpmock.GraphQL(query),
|
|
httpmock.StringResponse(fmt.Sprintf(
|
|
`{ "data": { "viewer": { "gists": { "nodes": [
|
|
{
|
|
"name": "1234",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "foo" }
|
|
],
|
|
"description": "octo match in the description",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
},
|
|
{
|
|
"name": "2345",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "foo" },
|
|
{ "name": "octo.txt", "text": "bar" }
|
|
],
|
|
"description": "match in the file name",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": false
|
|
},
|
|
{
|
|
"name": "3456",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "octo in the text" }
|
|
],
|
|
"description": "match in the file text",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
}
|
|
] } } } }`,
|
|
sixHoursAgo.Format(time.RFC3339),
|
|
)),
|
|
)
|
|
},
|
|
wantOut: heredoc.Docf(`
|
|
%[1]s[0;4;39mID %[1]s[0m %[1]s[0;4;39mDESCRIPTION %[1]s[0m %[1]s[0;4;39mFILES %[1]s[0m %[1]s[0;4;39mVISIBILITY%[1]s[0m %[1]s[0;4;39mUPDATED %[1]s[0m
|
|
1234 %[1]s[0;30;43mocto%[1]s[0m%[1]s[0;1;39m match in the description%[1]s[0m 1 file %[1]s[0;32mpublic %[1]s[0m %[1]s[38;5;242mabout 6 hours ago%[1]s[0m
|
|
2345 %[1]s[0;1;39mmatch in the file name %[1]s[0m %[1]s[0;30;43m2 files%[1]s[0m %[1]s[0;31msecret %[1]s[0m %[1]s[38;5;242mabout 6 hours ago%[1]s[0m
|
|
`, "\x1b"),
|
|
},
|
|
{
|
|
name: "filtered with content",
|
|
opts: &ListOptions{
|
|
Filter: regexp.MustCompile("octo"),
|
|
IncludeContent: true,
|
|
Visibility: "all",
|
|
},
|
|
nontty: true,
|
|
stubs: func(reg *httpmock.Registry) {
|
|
reg.Register(
|
|
httpmock.GraphQL(query),
|
|
httpmock.StringResponse(fmt.Sprintf(
|
|
`{ "data": { "viewer": { "gists": { "nodes": [
|
|
{
|
|
"name": "1234",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "foo" }
|
|
],
|
|
"description": "octo match in the description",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
},
|
|
{
|
|
"name": "2345",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "foo" },
|
|
{ "name": "octo.txt", "text": "bar" }
|
|
],
|
|
"description": "match in the file name",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": false
|
|
},
|
|
{
|
|
"name": "3456",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "octo in the text" }
|
|
],
|
|
"description": "match in the file text",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
}
|
|
] } } } }`,
|
|
absTime.Format(time.RFC3339),
|
|
)),
|
|
)
|
|
},
|
|
wantOut: heredoc.Doc(`
|
|
1234 main.txt
|
|
octo match in the description
|
|
|
|
2345 octo.txt
|
|
match in the file name
|
|
|
|
3456 main.txt
|
|
match in the file text
|
|
octo in the text
|
|
|
|
`),
|
|
},
|
|
{
|
|
name: "filtered with content (tty)",
|
|
opts: &ListOptions{
|
|
Filter: regexp.MustCompile("octo"),
|
|
IncludeContent: true,
|
|
Visibility: "all",
|
|
},
|
|
color: true,
|
|
stubs: func(reg *httpmock.Registry) {
|
|
reg.Register(
|
|
httpmock.GraphQL(query),
|
|
httpmock.StringResponse(fmt.Sprintf(
|
|
`{ "data": { "viewer": { "gists": { "nodes": [
|
|
{
|
|
"name": "1234",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "foo" }
|
|
],
|
|
"description": "octo match in the description",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
},
|
|
{
|
|
"name": "2345",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "foo" },
|
|
{ "name": "octo.txt", "text": "bar" }
|
|
],
|
|
"description": "match in the file name",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": false
|
|
},
|
|
{
|
|
"name": "3456",
|
|
"files": [
|
|
{ "name": "main.txt", "text": "octo in the text" }
|
|
],
|
|
"description": "match in the file text",
|
|
"updatedAt": "%[1]v",
|
|
"isPublic": true
|
|
}
|
|
] } } } }`,
|
|
sixHoursAgo.Format(time.RFC3339),
|
|
)),
|
|
)
|
|
},
|
|
wantOut: heredoc.Docf(`
|
|
%[1]s[0;34m1234%[1]s[0m %[1]s[0;32mmain.txt%[1]s[0m
|
|
%[1]s[0;30;43mocto%[1]s[0m%[1]s[0;1;39m match in the description%[1]s[0m
|
|
|
|
%[1]s[0;34m2345%[1]s[0m %[1]s[0;30;43mocto%[1]s[0m%[1]s[0;32m.txt%[1]s[0m
|
|
%[1]s[0;1;39mmatch in the file name%[1]s[0m
|
|
|
|
%[1]s[0;34m3456%[1]s[0m %[1]s[0;32mmain.txt%[1]s[0m
|
|
%[1]s[0;1;39mmatch in the file text%[1]s[0m
|
|
%[1]s[0;30;43mocto%[1]s[0m in the text
|
|
|
|
`, "\x1b"),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
reg := &httpmock.Registry{}
|
|
tt.stubs(reg)
|
|
|
|
tt.opts.HttpClient = func() (*http.Client, error) {
|
|
return &http.Client{Transport: reg}, nil
|
|
}
|
|
|
|
tt.opts.Config = func() (gh.Config, error) {
|
|
return config.NewBlankConfig(), nil
|
|
}
|
|
|
|
ios, _, stdout, _ := iostreams.Test()
|
|
ios.SetColorEnabled(tt.color)
|
|
ios.SetStdoutTTY(!tt.nontty)
|
|
tt.opts.IO = ios
|
|
|
|
if tt.opts.Limit == 0 {
|
|
tt.opts.Limit = 10
|
|
}
|
|
|
|
if tt.opts.Visibility == "" {
|
|
tt.opts.Visibility = "all"
|
|
}
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := listRun(tt.opts)
|
|
if tt.wantErr {
|
|
assert.Error(t, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
assert.Equal(t, tt.wantOut, stdout.String())
|
|
reg.Verify(t)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_highlightMatch(t *testing.T) {
|
|
regex := regexp.MustCompilePOSIX(`[Oo]cto`)
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
cs *iostreams.ColorScheme
|
|
want string
|
|
}{
|
|
{
|
|
name: "single match",
|
|
input: "Octo",
|
|
cs: &iostreams.ColorScheme{},
|
|
want: "Octo",
|
|
},
|
|
{
|
|
name: "single match (color)",
|
|
input: "Octo",
|
|
cs: &iostreams.ColorScheme{
|
|
Enabled: true,
|
|
},
|
|
want: "\x1b[0;30;43mOcto\x1b[0m",
|
|
},
|
|
{
|
|
name: "single match with extra",
|
|
input: "Hello, Octocat!",
|
|
cs: &iostreams.ColorScheme{},
|
|
want: "Hello, Octocat!",
|
|
},
|
|
{
|
|
name: "single match with extra (color)",
|
|
input: "Hello, Octocat!",
|
|
cs: &iostreams.ColorScheme{
|
|
Enabled: true,
|
|
},
|
|
want: "\x1b[0;34mHello, \x1b[0m\x1b[0;30;43mOcto\x1b[0m\x1b[0;34mcat!\x1b[0m",
|
|
},
|
|
{
|
|
name: "multiple matches",
|
|
input: "Octocat/octo",
|
|
cs: &iostreams.ColorScheme{},
|
|
want: "Octocat/octo",
|
|
},
|
|
{
|
|
name: "multiple matches (color)",
|
|
input: "Octocat/octo",
|
|
cs: &iostreams.ColorScheme{
|
|
Enabled: true,
|
|
},
|
|
want: "\x1b[0;30;43mOcto\x1b[0m\x1b[0;34mcat/\x1b[0m\x1b[0;30;43mocto\x1b[0m",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
matched := false
|
|
got, err := highlightMatch(tt.input, regex, &matched, tt.cs.Blue, tt.cs.Highlight)
|
|
assert.NoError(t, err)
|
|
assert.True(t, matched)
|
|
assert.Equal(t, tt.want, got)
|
|
})
|
|
}
|
|
}
|