cli/pkg/cmd/repo/edit/edit_test.go
2022-03-14 17:49:03 +00:00

342 lines
8.9 KiB
Go

package edit
import (
"bytes"
"context"
"io/ioutil"
"net/http"
"testing"
"github.com/cli/cli/v2/pkg/prompt"
"github.com/cli/cli/v2/internal/ghrepo"
"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"
"github.com/stretchr/testify/require"
)
func TestNewCmdEdit(t *testing.T) {
tests := []struct {
name string
args string
wantOpts EditOptions
wantErr string
}{
{
name: "change repo description",
args: "--description hello",
wantOpts: EditOptions{
Repository: ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
Edits: EditRepositoryInput{
Description: sp("hello"),
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
io, _, _, _ := iostreams.Test()
io.SetStdoutTTY(true)
io.SetStdinTTY(true)
io.SetStderrTTY(true)
f := &cmdutil.Factory{
IOStreams: io,
BaseRepo: func() (ghrepo.Interface, error) {
return ghrepo.New("OWNER", "REPO"), nil
},
HttpClient: func() (*http.Client, error) {
return nil, nil
},
}
argv, err := shlex.Split(tt.args)
assert.NoError(t, err)
var gotOpts *EditOptions
cmd := NewCmdEdit(f, func(opts *EditOptions) error {
gotOpts = opts
return nil
})
cmd.Flags().BoolP("help", "x", false, "")
cmd.SetArgs(argv)
cmd.SetIn(&bytes.Buffer{})
cmd.SetOut(ioutil.Discard)
cmd.SetErr(ioutil.Discard)
_, err = cmd.ExecuteC()
if tt.wantErr != "" {
assert.EqualError(t, err, tt.wantErr)
return
}
require.NoError(t, err)
assert.Equal(t, ghrepo.FullName(tt.wantOpts.Repository), ghrepo.FullName(gotOpts.Repository))
assert.Equal(t, tt.wantOpts.Edits, gotOpts.Edits)
})
}
}
func Test_editRun(t *testing.T) {
tests := []struct {
name string
opts EditOptions
httpStubs func(*testing.T, *httpmock.Registry)
wantsStderr string
wantsErr string
}{
{
name: "change name and description",
opts: EditOptions{
Repository: ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
Edits: EditRepositoryInput{
Homepage: sp("newURL"),
Description: sp("hello world!"),
},
},
httpStubs: func(t *testing.T, r *httpmock.Registry) {
r.Register(
httpmock.REST("PATCH", "repos/OWNER/REPO"),
httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
assert.Equal(t, 2, len(payload))
assert.Equal(t, "newURL", payload["homepage"])
assert.Equal(t, "hello world!", payload["description"])
}))
},
},
{
name: "add and remove topics",
opts: EditOptions{
Repository: ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
AddTopics: []string{"topic1", "topic2"},
RemoveTopics: []string{"topic3"},
},
httpStubs: func(t *testing.T, r *httpmock.Registry) {
r.Register(
httpmock.REST("GET", "repos/OWNER/REPO/topics"),
httpmock.StringResponse(`{"names":["topic2", "topic3", "go"]}`))
r.Register(
httpmock.REST("PUT", "repos/OWNER/REPO/topics"),
httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
assert.Equal(t, 1, len(payload))
assert.Equal(t, []interface{}{"topic2", "go", "topic1"}, payload["names"])
}))
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
io, _, _, _ := iostreams.Test()
io.SetStdoutTTY(true)
io.SetStdinTTY(true)
io.SetStderrTTY(true)
httpReg := &httpmock.Registry{}
defer httpReg.Verify(t)
if tt.httpStubs != nil {
tt.httpStubs(t, httpReg)
}
opts := &tt.opts
opts.HTTPClient = &http.Client{Transport: httpReg}
opts.IO = io
err := editRun(context.Background(), opts)
if tt.wantsErr == "" {
require.NoError(t, err)
} else {
assert.EqualError(t, err, tt.wantsErr)
return
}
})
}
}
func Test_editRun_interactive(t *testing.T) {
tests := []struct {
name string
opts EditOptions
askStubs func(*prompt.AskStubber)
httpStubs func(*testing.T, *httpmock.Registry)
wantsStderr string
wantsErr string
}{
{
name: "updates repo description",
opts: EditOptions{
Repository: ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
InteractiveMode: true,
},
askStubs: func(as *prompt.AskStubber) {
as.StubPrompt("What do you want to edit?").AnswerWith([]string{"Description"})
as.StubPrompt("Description of the repository").AnswerWith("awesome repo description")
},
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(
httpmock.GraphQL(`query RepositoryInfo\b`),
httpmock.StringResponse(`
{
"data": {
"repository": {
"description": "old description",
"homePageUrl": "https://url.com",
"defaultBranchRef": {
"name": "main"
},
"isInOrganization": false,
"repositoryTopics": {
"nodes": [{
"topic": {
"name": "x"
}
}]
}
}
}
}`))
reg.Register(
httpmock.REST("PATCH", "repos/OWNER/REPO"),
httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
assert.Equal(t, "awesome repo description", payload["description"])
}))
},
},
{
name: "updates repo topics",
opts: EditOptions{
Repository: ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
InteractiveMode: true,
},
askStubs: func(as *prompt.AskStubber) {
as.StubPrompt("What do you want to edit?").AnswerWith([]string{"Description", "Topics"})
as.StubPrompt("Description of the repository").AnswerWith("awesome repo description")
as.StubPrompt("Add topics?(csv format)").AnswerWith("a,b,c,d")
as.StubPrompt("Remove Topics").AnswerWith([]string{"x"})
},
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(
httpmock.GraphQL(`query RepositoryInfo\b`),
httpmock.StringResponse(`
{
"data": {
"repository": {
"description": "old description",
"homePageUrl": "https://url.com",
"defaultBranchRef": {
"name": "main"
},
"isInOrganization": false,
"repositoryTopics": {
"nodes": [{
"topic": {
"name": "x"
}
}]
}
}
}
}`))
reg.Register(
httpmock.REST("PATCH", "repos/OWNER/REPO"),
httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
assert.Equal(t, "awesome repo description", payload["description"])
}))
reg.Register(
httpmock.REST("PUT", "repos/OWNER/REPO/topics"),
httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
assert.Equal(t, []interface{}{"a", "b", "c", "d"}, payload["names"])
}))
},
},
{
name: "updates repo merge options",
opts: EditOptions{
Repository: ghrepo.NewWithHost("OWNER", "REPO", "github.com"),
InteractiveMode: true,
},
askStubs: func(as *prompt.AskStubber) {
as.StubPrompt("What do you want to edit?").AnswerWith([]string{"Merge Options"})
as.StubPrompt("Allowed merge strategies").AnswerWith([]string{allowMergeCommits, allowRebaseMerge})
as.StubPrompt("Enable Auto Merge?").AnswerWith(false)
as.StubPrompt("Automatically delete head branches after merging?").AnswerWith(false)
},
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(
httpmock.GraphQL(`query RepositoryInfo\b`),
httpmock.StringResponse(`
{
"data": {
"repository": {
"description": "old description",
"homePageUrl": "https://url.com",
"defaultBranchRef": {
"name": "main"
},
"isInOrganization": false,
"squashMergeAllowed": false,
"rebaseMergeAllowed": true,
"mergeCommitAllowed": true,
"deleteBranchOnMerge": false,
"repositoryTopics": {
"nodes": [{
"topic": {
"name": "x"
}
}]
}
}
}
}`))
reg.Register(
httpmock.REST("PATCH", "repos/OWNER/REPO"),
httpmock.RESTPayload(200, `{}`, func(payload map[string]interface{}) {
assert.Equal(t, true, payload["allow_merge_commit"])
assert.Equal(t, false, payload["allow_squash_merge"])
assert.Equal(t, true, payload["allow_rebase_merge"])
}))
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
io, _, _, _ := iostreams.Test()
io.SetStdoutTTY(true)
io.SetStdinTTY(true)
io.SetStderrTTY(true)
httpReg := &httpmock.Registry{}
defer httpReg.Verify(t)
if tt.httpStubs != nil {
tt.httpStubs(t, httpReg)
}
opts := &tt.opts
opts.HTTPClient = &http.Client{Transport: httpReg}
opts.IO = io
as := prompt.NewAskStubber(t)
if tt.askStubs != nil {
tt.askStubs(as)
}
err := editRun(context.Background(), opts)
if tt.wantsErr == "" {
require.NoError(t, err)
} else {
assert.EqualError(t, err, tt.wantsErr)
return
}
})
}
}
func sp(v string) *string {
return &v
}