cli/pkg/cmd/pr/diff/diff_test.go
2022-04-26 13:07:44 +02:00

292 lines
6.9 KiB
Go

package diff
import (
"bytes"
"fmt"
"io"
"net/http"
"strings"
"testing"
"github.com/cli/cli/v2/api"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/pkg/cmd/pr/shared"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/httpmock"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/google/go-cmp/cmp"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_NewCmdDiff(t *testing.T) {
tests := []struct {
name string
args string
isTTY bool
want DiffOptions
wantErr string
}{
{
name: "number argument",
args: "123",
isTTY: true,
want: DiffOptions{
SelectorArg: "123",
UseColor: true,
},
},
{
name: "no argument",
args: "",
isTTY: true,
want: DiffOptions{
SelectorArg: "",
UseColor: true,
},
},
{
name: "no color when redirected",
args: "",
isTTY: false,
want: DiffOptions{
SelectorArg: "",
UseColor: false,
},
},
{
name: "force color",
args: "--color always",
isTTY: false,
want: DiffOptions{
SelectorArg: "",
UseColor: true,
},
},
{
name: "disable color",
args: "--color never",
isTTY: true,
want: DiffOptions{
SelectorArg: "",
UseColor: false,
},
},
{
name: "no argument with --repo override",
args: "-R owner/repo",
isTTY: true,
wantErr: "argument required when using the `--repo` flag",
},
{
name: "invalid --color argument",
args: "--color doublerainbow",
isTTY: true,
wantErr: "invalid argument \"doublerainbow\" for \"--color\" flag: valid values are {always|never|auto}",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ios, _, _, _ := iostreams.Test()
ios.SetStdoutTTY(tt.isTTY)
ios.SetStdinTTY(tt.isTTY)
ios.SetStderrTTY(tt.isTTY)
ios.SetColorEnabled(tt.isTTY)
f := &cmdutil.Factory{
IOStreams: ios,
}
var opts *DiffOptions
cmd := NewCmdDiff(f, func(o *DiffOptions) error {
opts = o
return nil
})
cmd.PersistentFlags().StringP("repo", "R", "", "")
argv, err := shlex.Split(tt.args)
require.NoError(t, err)
cmd.SetArgs(argv)
cmd.SetIn(&bytes.Buffer{})
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
_, err = cmd.ExecuteC()
if tt.wantErr != "" {
require.EqualError(t, err, tt.wantErr)
return
} else {
require.NoError(t, err)
}
assert.Equal(t, tt.want.SelectorArg, opts.SelectorArg)
assert.Equal(t, tt.want.UseColor, opts.UseColor)
})
}
}
func Test_diffRun(t *testing.T) {
pr := &api.PullRequest{Number: 123}
tests := []struct {
name string
opts DiffOptions
rawDiff string
wantAccept string
wantStdout string
}{
{
name: "no color",
opts: DiffOptions{
SelectorArg: "123",
UseColor: false,
Patch: false,
},
rawDiff: fmt.Sprintf(testDiff, "", "", "", ""),
wantAccept: "application/vnd.github.v3.diff",
wantStdout: fmt.Sprintf(testDiff, "", "", "", ""),
},
{
name: "with color",
opts: DiffOptions{
SelectorArg: "123",
UseColor: true,
Patch: false,
},
rawDiff: fmt.Sprintf(testDiff, "", "", "", ""),
wantAccept: "application/vnd.github.v3.diff",
wantStdout: fmt.Sprintf(testDiff, "\x1b[m", "\x1b[1;38m", "\x1b[32m", "\x1b[31m"),
},
{
name: "patch format",
opts: DiffOptions{
SelectorArg: "123",
UseColor: false,
Patch: true,
},
rawDiff: fmt.Sprintf(testDiff, "", "", "", ""),
wantAccept: "application/vnd.github.v3.patch",
wantStdout: fmt.Sprintf(testDiff, "", "", "", ""),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
httpReg := &httpmock.Registry{}
defer httpReg.Verify(t)
var gotAccept string
httpReg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/pulls/123"),
func(req *http.Request) (*http.Response, error) {
gotAccept = req.Header.Get("Accept")
return &http.Response{
StatusCode: 200,
Request: req,
Body: io.NopCloser(strings.NewReader(tt.rawDiff)),
}, nil
})
opts := tt.opts
opts.HttpClient = func() (*http.Client, error) {
return &http.Client{Transport: httpReg}, nil
}
ios, _, stdout, stderr := iostreams.Test()
opts.IO = ios
finder := shared.NewMockFinder("123", pr, ghrepo.New("OWNER", "REPO"))
finder.ExpectFields([]string{"number"})
opts.Finder = finder
if err := diffRun(&opts); err != nil {
t.Fatalf("unexpected error: %s", err)
}
if diff := cmp.Diff(tt.wantStdout, stdout.String()); diff != "" {
t.Errorf("command output did not match:\n%s", diff)
}
if stderr.String() != "" {
t.Errorf("unexpected stderr output: %s", stderr.String())
}
if gotAccept != tt.wantAccept {
t.Errorf("unexpected Accept header: %s", gotAccept)
}
})
}
}
const testDiff = `%[2]sdiff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml%[1]s
%[2]sindex 73974448..b7fc0154 100644%[1]s
%[2]s--- a/.github/workflows/releases.yml%[1]s
%[2]s+++ b/.github/workflows/releases.yml%[1]s
@@ -44,6 +44,11 @@ jobs:
token: ${{secrets.SITE_GITHUB_TOKEN}}
- name: Publish documentation site
if: "!contains(github.ref, '-')" # skip prereleases
%[3]s+ env:%[1]s
%[3]s+ GIT_COMMITTER_NAME: cli automation%[1]s
%[3]s+ GIT_AUTHOR_NAME: cli automation%[1]s
%[3]s+ GIT_COMMITTER_EMAIL: noreply@github.com%[1]s
%[3]s+ GIT_AUTHOR_EMAIL: noreply@github.com%[1]s
run: make site-publish
- name: Move project cards
if: "!contains(github.ref, '-')" # skip prereleases
%[2]sdiff --git a/Makefile b/Makefile%[1]s
%[2]sindex f2b4805c..3d7bd0f9 100644%[1]s
%[2]s--- a/Makefile%[1]s
%[2]s+++ b/Makefile%[1]s
@@ -22,8 +22,8 @@ test:
go test ./...
.PHONY: test
%[4]s-site:%[1]s
%[4]s- git clone https://github.com/github/cli.github.com.git "$@"%[1]s
%[3]s+site: bin/gh%[1]s
%[3]s+ bin/gh repo clone github/cli.github.com "$@"%[1]s
site-docs: site
git -C site pull
`
func Test_colorDiffLines(t *testing.T) {
inputs := []struct {
input, output string
}{
{
input: "",
output: "",
},
{
input: "\n",
output: "\n",
},
{
input: "foo\nbar\nbaz\n",
output: "foo\nbar\nbaz\n",
},
{
input: "foo\nbar\nbaz",
output: "foo\nbar\nbaz\n",
},
{
input: fmt.Sprintf("+foo\n-b%sr\n+++ baz\n", strings.Repeat("a", 2*lineBufferSize)),
output: fmt.Sprintf(
"%[4]s+foo%[2]s\n%[5]s-b%[1]sr%[2]s\n%[3]s+++ baz%[2]s\n",
strings.Repeat("a", 2*lineBufferSize),
"\x1b[m",
"\x1b[1;38m",
"\x1b[32m",
"\x1b[31m",
),
},
}
for _, tt := range inputs {
buf := bytes.Buffer{}
if err := colorDiffLines(&buf, strings.NewReader(tt.input)); err != nil {
t.Fatalf("unexpected error: %s", err)
}
if got := buf.String(); got != tt.output {
t.Errorf("expected: %q, got: %q", tt.output, got)
}
}
}