github.com/andrewhsu/cli/v2@v2.0.1-0.20210910131313-d4b4061f5b89/pkg/cmd/gist/edit/edit_test.go (about)

     1  package edit
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"path/filepath"
     9  	"testing"
    10  
    11  	"github.com/andrewhsu/cli/v2/internal/config"
    12  	"github.com/andrewhsu/cli/v2/pkg/cmd/gist/shared"
    13  	"github.com/andrewhsu/cli/v2/pkg/cmdutil"
    14  	"github.com/andrewhsu/cli/v2/pkg/httpmock"
    15  	"github.com/andrewhsu/cli/v2/pkg/iostreams"
    16  	"github.com/andrewhsu/cli/v2/pkg/prompt"
    17  	"github.com/google/shlex"
    18  	"github.com/stretchr/testify/assert"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  func Test_getFilesToAdd(t *testing.T) {
    23  	fileToAdd := filepath.Join(t.TempDir(), "gist-test.txt")
    24  	err := ioutil.WriteFile(fileToAdd, []byte("hello"), 0600)
    25  	require.NoError(t, err)
    26  
    27  	gf, err := getFilesToAdd(fileToAdd)
    28  	require.NoError(t, err)
    29  
    30  	filename := filepath.Base(fileToAdd)
    31  	assert.Equal(t, map[string]*shared.GistFile{
    32  		filename: {
    33  			Filename: filename,
    34  			Content:  "hello",
    35  		},
    36  	}, gf)
    37  }
    38  
    39  func TestNewCmdEdit(t *testing.T) {
    40  	tests := []struct {
    41  		name  string
    42  		cli   string
    43  		wants EditOptions
    44  	}{
    45  		{
    46  			name: "no flags",
    47  			cli:  "123",
    48  			wants: EditOptions{
    49  				Selector: "123",
    50  			},
    51  		},
    52  		{
    53  			name: "filename",
    54  			cli:  "123 --filename cool.md",
    55  			wants: EditOptions{
    56  				Selector:     "123",
    57  				EditFilename: "cool.md",
    58  			},
    59  		},
    60  		{
    61  			name: "add",
    62  			cli:  "123 --add cool.md",
    63  			wants: EditOptions{
    64  				Selector:    "123",
    65  				AddFilename: "cool.md",
    66  			},
    67  		},
    68  	}
    69  
    70  	for _, tt := range tests {
    71  		t.Run(tt.name, func(t *testing.T) {
    72  			f := &cmdutil.Factory{}
    73  
    74  			argv, err := shlex.Split(tt.cli)
    75  			assert.NoError(t, err)
    76  
    77  			var gotOpts *EditOptions
    78  			cmd := NewCmdEdit(f, func(opts *EditOptions) error {
    79  				gotOpts = opts
    80  				return nil
    81  			})
    82  			cmd.SetArgs(argv)
    83  			cmd.SetIn(&bytes.Buffer{})
    84  			cmd.SetOut(&bytes.Buffer{})
    85  			cmd.SetErr(&bytes.Buffer{})
    86  
    87  			_, err = cmd.ExecuteC()
    88  			assert.NoError(t, err)
    89  
    90  			assert.Equal(t, tt.wants.EditFilename, gotOpts.EditFilename)
    91  			assert.Equal(t, tt.wants.AddFilename, gotOpts.AddFilename)
    92  			assert.Equal(t, tt.wants.Selector, gotOpts.Selector)
    93  		})
    94  	}
    95  }
    96  
    97  func Test_editRun(t *testing.T) {
    98  	fileToAdd := filepath.Join(t.TempDir(), "gist-test.txt")
    99  	err := ioutil.WriteFile(fileToAdd, []byte("hello"), 0600)
   100  	require.NoError(t, err)
   101  
   102  	tests := []struct {
   103  		name       string
   104  		opts       *EditOptions
   105  		gist       *shared.Gist
   106  		httpStubs  func(*httpmock.Registry)
   107  		askStubs   func(*prompt.AskStubber)
   108  		nontty     bool
   109  		wantErr    string
   110  		wantParams map[string]interface{}
   111  	}{
   112  		{
   113  			name:    "no such gist",
   114  			wantErr: "gist not found: 1234",
   115  		},
   116  		{
   117  			name: "one file",
   118  			gist: &shared.Gist{
   119  				ID: "1234",
   120  				Files: map[string]*shared.GistFile{
   121  					"cicada.txt": {
   122  						Filename: "cicada.txt",
   123  						Content:  "bwhiizzzbwhuiiizzzz",
   124  						Type:     "text/plain",
   125  					},
   126  				},
   127  				Owner: &shared.GistOwner{Login: "octocat"},
   128  			},
   129  			httpStubs: func(reg *httpmock.Registry) {
   130  				reg.Register(httpmock.REST("POST", "gists/1234"),
   131  					httpmock.StatusStringResponse(201, "{}"))
   132  			},
   133  			wantParams: map[string]interface{}{
   134  				"description": "",
   135  				"updated_at":  "0001-01-01T00:00:00Z",
   136  				"public":      false,
   137  				"files": map[string]interface{}{
   138  					"cicada.txt": map[string]interface{}{
   139  						"content":  "new file content",
   140  						"filename": "cicada.txt",
   141  						"type":     "text/plain",
   142  					},
   143  				},
   144  			},
   145  		},
   146  		{
   147  			name: "multiple files, submit",
   148  			askStubs: func(as *prompt.AskStubber) {
   149  				as.StubOne("unix.md")
   150  				as.StubOne("Submit")
   151  			},
   152  			gist: &shared.Gist{
   153  				ID:          "1234",
   154  				Description: "catbug",
   155  				Files: map[string]*shared.GistFile{
   156  					"cicada.txt": {
   157  						Filename: "cicada.txt",
   158  						Content:  "bwhiizzzbwhuiiizzzz",
   159  						Type:     "text/plain",
   160  					},
   161  					"unix.md": {
   162  						Filename: "unix.md",
   163  						Content:  "meow",
   164  						Type:     "application/markdown",
   165  					},
   166  				},
   167  				Owner: &shared.GistOwner{Login: "octocat"},
   168  			},
   169  			httpStubs: func(reg *httpmock.Registry) {
   170  				reg.Register(httpmock.REST("POST", "gists/1234"),
   171  					httpmock.StatusStringResponse(201, "{}"))
   172  			},
   173  			wantParams: map[string]interface{}{
   174  				"description": "catbug",
   175  				"updated_at":  "0001-01-01T00:00:00Z",
   176  				"public":      false,
   177  				"files": map[string]interface{}{
   178  					"cicada.txt": map[string]interface{}{
   179  						"content":  "bwhiizzzbwhuiiizzzz",
   180  						"filename": "cicada.txt",
   181  						"type":     "text/plain",
   182  					},
   183  					"unix.md": map[string]interface{}{
   184  						"content":  "new file content",
   185  						"filename": "unix.md",
   186  						"type":     "application/markdown",
   187  					},
   188  				},
   189  			},
   190  		},
   191  		{
   192  			name: "multiple files, cancel",
   193  			askStubs: func(as *prompt.AskStubber) {
   194  				as.StubOne("unix.md")
   195  				as.StubOne("Cancel")
   196  			},
   197  			wantErr: "CancelError",
   198  			gist: &shared.Gist{
   199  				ID: "1234",
   200  				Files: map[string]*shared.GistFile{
   201  					"cicada.txt": {
   202  						Filename: "cicada.txt",
   203  						Content:  "bwhiizzzbwhuiiizzzz",
   204  						Type:     "text/plain",
   205  					},
   206  					"unix.md": {
   207  						Filename: "unix.md",
   208  						Content:  "meow",
   209  						Type:     "application/markdown",
   210  					},
   211  				},
   212  				Owner: &shared.GistOwner{Login: "octocat"},
   213  			},
   214  		},
   215  		{
   216  			name: "not change",
   217  			gist: &shared.Gist{
   218  				ID: "1234",
   219  				Files: map[string]*shared.GistFile{
   220  					"cicada.txt": {
   221  						Filename: "cicada.txt",
   222  						Content:  "new file content",
   223  						Type:     "text/plain",
   224  					},
   225  				},
   226  				Owner: &shared.GistOwner{Login: "octocat"},
   227  			},
   228  		},
   229  		{
   230  			name: "another user's gist",
   231  			gist: &shared.Gist{
   232  				ID: "1234",
   233  				Files: map[string]*shared.GistFile{
   234  					"cicada.txt": {
   235  						Filename: "cicada.txt",
   236  						Content:  "bwhiizzzbwhuiiizzzz",
   237  						Type:     "text/plain",
   238  					},
   239  				},
   240  				Owner: &shared.GistOwner{Login: "octocat2"},
   241  			},
   242  			wantErr: "You do not own this gist.",
   243  		},
   244  		{
   245  			name: "add file to existing gist",
   246  			gist: &shared.Gist{
   247  				ID: "1234",
   248  				Files: map[string]*shared.GistFile{
   249  					"sample.txt": {
   250  						Filename: "sample.txt",
   251  						Content:  "bwhiizzzbwhuiiizzzz",
   252  						Type:     "text/plain",
   253  					},
   254  				},
   255  				Owner: &shared.GistOwner{Login: "octocat"},
   256  			},
   257  			httpStubs: func(reg *httpmock.Registry) {
   258  				reg.Register(httpmock.REST("POST", "gists/1234"),
   259  					httpmock.StatusStringResponse(201, "{}"))
   260  			},
   261  			opts: &EditOptions{
   262  				AddFilename: fileToAdd,
   263  			},
   264  		},
   265  	}
   266  
   267  	for _, tt := range tests {
   268  		reg := &httpmock.Registry{}
   269  		if tt.gist == nil {
   270  			reg.Register(httpmock.REST("GET", "gists/1234"),
   271  				httpmock.StatusStringResponse(404, "Not Found"))
   272  		} else {
   273  			reg.Register(httpmock.REST("GET", "gists/1234"),
   274  				httpmock.JSONResponse(tt.gist))
   275  			reg.Register(httpmock.GraphQL(`query UserCurrent\b`),
   276  				httpmock.StringResponse(`{"data":{"viewer":{"login":"octocat"}}}`))
   277  		}
   278  
   279  		if tt.httpStubs != nil {
   280  			tt.httpStubs(reg)
   281  		}
   282  
   283  		as, teardown := prompt.InitAskStubber()
   284  		defer teardown()
   285  		if tt.askStubs != nil {
   286  			tt.askStubs(as)
   287  		}
   288  
   289  		if tt.opts == nil {
   290  			tt.opts = &EditOptions{}
   291  		}
   292  
   293  		tt.opts.Edit = func(_, _, _ string, _ *iostreams.IOStreams) (string, error) {
   294  			return "new file content", nil
   295  		}
   296  
   297  		tt.opts.HttpClient = func() (*http.Client, error) {
   298  			return &http.Client{Transport: reg}, nil
   299  		}
   300  		io, _, stdout, stderr := iostreams.Test()
   301  		io.SetStdoutTTY(!tt.nontty)
   302  		io.SetStdinTTY(!tt.nontty)
   303  		tt.opts.IO = io
   304  		tt.opts.Selector = "1234"
   305  
   306  		tt.opts.Config = func() (config.Config, error) {
   307  			return config.NewBlankConfig(), nil
   308  		}
   309  
   310  		t.Run(tt.name, func(t *testing.T) {
   311  			err := editRun(tt.opts)
   312  			reg.Verify(t)
   313  			if tt.wantErr != "" {
   314  				assert.EqualError(t, err, tt.wantErr)
   315  				return
   316  			}
   317  			assert.NoError(t, err)
   318  
   319  			if tt.wantParams != nil {
   320  				bodyBytes, _ := ioutil.ReadAll(reg.Requests[2].Body)
   321  				reqBody := make(map[string]interface{})
   322  				err = json.Unmarshal(bodyBytes, &reqBody)
   323  				if err != nil {
   324  					t.Fatalf("error decoding JSON: %v", err)
   325  				}
   326  				assert.Equal(t, tt.wantParams, reqBody)
   327  			}
   328  
   329  			assert.Equal(t, "", stdout.String())
   330  			assert.Equal(t, "", stderr.String())
   331  		})
   332  	}
   333  }