github.com/secman-team/gh-api@v1.8.2/pkg/cmd/repo/view/view_test.go (about)

     1  package view
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"net/http"
     7  	"testing"
     8  
     9  	"github.com/MakeNowJust/heredoc"
    10  	"github.com/secman-team/gh-api/core/ghrepo"
    11  	"github.com/secman-team/gh-api/core/run"
    12  	"github.com/secman-team/gh-api/pkg/cmdutil"
    13  	"github.com/secman-team/gh-api/pkg/httpmock"
    14  	"github.com/secman-team/gh-api/pkg/iostreams"
    15  	"github.com/google/shlex"
    16  	"github.com/stretchr/testify/assert"
    17  )
    18  
    19  func TestNewCmdView(t *testing.T) {
    20  	tests := []struct {
    21  		name     string
    22  		cli      string
    23  		wants    ViewOptions
    24  		wantsErr bool
    25  	}{
    26  		{
    27  			name: "no args",
    28  			cli:  "",
    29  			wants: ViewOptions{
    30  				RepoArg: "",
    31  				Web:     false,
    32  			},
    33  		},
    34  		{
    35  			name: "sets repo arg",
    36  			cli:  "some/repo",
    37  			wants: ViewOptions{
    38  				RepoArg: "some/repo",
    39  				Web:     false,
    40  			},
    41  		},
    42  		{
    43  			name: "sets web",
    44  			cli:  "-w",
    45  			wants: ViewOptions{
    46  				RepoArg: "",
    47  				Web:     true,
    48  			},
    49  		},
    50  		{
    51  			name: "sets branch",
    52  			cli:  "-b feat/awesome",
    53  			wants: ViewOptions{
    54  				RepoArg: "",
    55  				Branch:  "feat/awesome",
    56  			},
    57  		},
    58  	}
    59  
    60  	for _, tt := range tests {
    61  		t.Run(tt.name, func(t *testing.T) {
    62  			io, _, _, _ := iostreams.Test()
    63  
    64  			f := &cmdutil.Factory{
    65  				IOStreams: io,
    66  			}
    67  
    68  			// THOUGHT: this seems ripe for cmdutil. It's almost identical to the set up for the same test
    69  			// in gist create.
    70  			argv, err := shlex.Split(tt.cli)
    71  			assert.NoError(t, err)
    72  
    73  			var gotOpts *ViewOptions
    74  			cmd := NewCmdView(f, func(opts *ViewOptions) error {
    75  				gotOpts = opts
    76  				return nil
    77  			})
    78  			cmd.SetArgs(argv)
    79  			cmd.SetIn(&bytes.Buffer{})
    80  			cmd.SetOut(&bytes.Buffer{})
    81  			cmd.SetErr(&bytes.Buffer{})
    82  
    83  			_, err = cmd.ExecuteC()
    84  			if tt.wantsErr {
    85  				assert.Error(t, err)
    86  				return
    87  			}
    88  			assert.NoError(t, err)
    89  
    90  			assert.Equal(t, tt.wants.Web, gotOpts.Web)
    91  			assert.Equal(t, tt.wants.Branch, gotOpts.Branch)
    92  			assert.Equal(t, tt.wants.RepoArg, gotOpts.RepoArg)
    93  		})
    94  	}
    95  }
    96  
    97  func Test_RepoView_Web(t *testing.T) {
    98  	tests := []struct {
    99  		name       string
   100  		stdoutTTY  bool
   101  		wantStderr string
   102  		wantBrowse string
   103  	}{
   104  		{
   105  			name:       "tty",
   106  			stdoutTTY:  true,
   107  			wantStderr: "Opening github.com/OWNER/REPO in your browser.\n",
   108  			wantBrowse: "https://github.com/OWNER/REPO",
   109  		},
   110  		{
   111  			name:       "nontty",
   112  			stdoutTTY:  false,
   113  			wantStderr: "",
   114  			wantBrowse: "https://github.com/OWNER/REPO",
   115  		},
   116  	}
   117  
   118  	for _, tt := range tests {
   119  		reg := &httpmock.Registry{}
   120  		reg.StubRepoInfoResponse("OWNER", "REPO", "main")
   121  
   122  		browser := &cmdutil.TestBrowser{}
   123  		opts := &ViewOptions{
   124  			Web: true,
   125  			HttpClient: func() (*http.Client, error) {
   126  				return &http.Client{Transport: reg}, nil
   127  			},
   128  			BaseRepo: func() (ghrepo.Interface, error) {
   129  				return ghrepo.New("OWNER", "REPO"), nil
   130  			},
   131  			Browser: browser,
   132  		}
   133  
   134  		io, _, stdout, stderr := iostreams.Test()
   135  
   136  		opts.IO = io
   137  
   138  		t.Run(tt.name, func(t *testing.T) {
   139  			io.SetStdoutTTY(tt.stdoutTTY)
   140  
   141  			_, teardown := run.Stub()
   142  			defer teardown(t)
   143  
   144  			if err := viewRun(opts); err != nil {
   145  				t.Errorf("viewRun() error = %v", err)
   146  			}
   147  			assert.Equal(t, "", stdout.String())
   148  			assert.Equal(t, tt.wantStderr, stderr.String())
   149  			reg.Verify(t)
   150  			browser.Verify(t, tt.wantBrowse)
   151  		})
   152  	}
   153  }
   154  
   155  func Test_ViewRun(t *testing.T) {
   156  	tests := []struct {
   157  		name       string
   158  		opts       *ViewOptions
   159  		repoName   string
   160  		stdoutTTY  bool
   161  		wantOut    string
   162  		wantStderr string
   163  		wantErr    bool
   164  	}{
   165  		{
   166  			name: "nontty",
   167  			wantOut: heredoc.Doc(`
   168  				name:	OWNER/REPO
   169  				description:	social distancing
   170  				--
   171  				# truly cool readme check it out
   172  				`),
   173  		},
   174  		{
   175  			name:     "url arg",
   176  			repoName: "jill/valentine",
   177  			opts: &ViewOptions{
   178  				RepoArg: "https://github.com/jill/valentine",
   179  			},
   180  			stdoutTTY: true,
   181  			wantOut: heredoc.Doc(`
   182  				jill/valentine
   183  				social distancing
   184  
   185  
   186  				  # truly cool readme check it out                                            
   187  
   188  
   189  
   190  				View this repository on GitHub: https://github.com/jill/valentine
   191  			`),
   192  		},
   193  		{
   194  			name:     "name arg",
   195  			repoName: "jill/valentine",
   196  			opts: &ViewOptions{
   197  				RepoArg: "jill/valentine",
   198  			},
   199  			stdoutTTY: true,
   200  			wantOut: heredoc.Doc(`
   201  				jill/valentine
   202  				social distancing
   203  
   204  
   205  				  # truly cool readme check it out                                            
   206  
   207  
   208  
   209  				View this repository on GitHub: https://github.com/jill/valentine
   210  			`),
   211  		},
   212  		{
   213  			name: "branch arg",
   214  			opts: &ViewOptions{
   215  				Branch: "feat/awesome",
   216  			},
   217  			stdoutTTY: true,
   218  			wantOut: heredoc.Doc(`
   219  				OWNER/REPO
   220  				social distancing
   221  
   222  
   223  				  # truly cool readme check it out                                            
   224  
   225  
   226  
   227  				View this repository on GitHub: https://github.com/OWNER/REPO/tree/feat%2Fawesome
   228  			`),
   229  		},
   230  		{
   231  			name:      "no args",
   232  			stdoutTTY: true,
   233  			wantOut: heredoc.Doc(`
   234  				OWNER/REPO
   235  				social distancing
   236  
   237  
   238  				  # truly cool readme check it out                                            
   239  
   240  
   241  
   242  				View this repository on GitHub: https://github.com/OWNER/REPO
   243  			`),
   244  		},
   245  	}
   246  	for _, tt := range tests {
   247  		if tt.opts == nil {
   248  			tt.opts = &ViewOptions{}
   249  		}
   250  
   251  		if tt.repoName == "" {
   252  			tt.repoName = "OWNER/REPO"
   253  		}
   254  
   255  		tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
   256  			repo, _ := ghrepo.FromFullName(tt.repoName)
   257  			return repo, nil
   258  		}
   259  
   260  		reg := &httpmock.Registry{}
   261  		reg.Register(
   262  			httpmock.GraphQL(`query RepositoryInfo\b`),
   263  			httpmock.StringResponse(`
   264  		{ "data": {
   265  			"repository": {
   266  			"description": "social distancing"
   267  		} } }`))
   268  		reg.Register(
   269  			httpmock.REST("GET", fmt.Sprintf("repos/%s/readme", tt.repoName)),
   270  			httpmock.StringResponse(`
   271  		{ "name": "readme.md",
   272  		"content": "IyB0cnVseSBjb29sIHJlYWRtZSBjaGVjayBpdCBvdXQ="}`))
   273  
   274  		tt.opts.HttpClient = func() (*http.Client, error) {
   275  			return &http.Client{Transport: reg}, nil
   276  		}
   277  
   278  		io, _, stdout, stderr := iostreams.Test()
   279  		tt.opts.IO = io
   280  
   281  		t.Run(tt.name, func(t *testing.T) {
   282  			io.SetStdoutTTY(tt.stdoutTTY)
   283  
   284  			if err := viewRun(tt.opts); (err != nil) != tt.wantErr {
   285  				t.Errorf("viewRun() error = %v, wantErr %v", err, tt.wantErr)
   286  			}
   287  			assert.Equal(t, tt.wantStderr, stderr.String())
   288  			assert.Equal(t, tt.wantOut, stdout.String())
   289  			reg.Verify(t)
   290  		})
   291  	}
   292  }
   293  
   294  func Test_ViewRun_NonMarkdownReadme(t *testing.T) {
   295  	tests := []struct {
   296  		name      string
   297  		stdoutTTY bool
   298  		wantOut   string
   299  	}{
   300  		{
   301  			name: "tty",
   302  			wantOut: heredoc.Doc(`
   303  			OWNER/REPO
   304  			social distancing
   305  
   306  			# truly cool readme check it out
   307  
   308  			View this repository on GitHub: https://github.com/OWNER/REPO
   309  			`),
   310  			stdoutTTY: true,
   311  		},
   312  		{
   313  			name: "nontty",
   314  			wantOut: heredoc.Doc(`
   315  			name:	OWNER/REPO
   316  			description:	social distancing
   317  			--
   318  			# truly cool readme check it out
   319  			`),
   320  		},
   321  	}
   322  
   323  	for _, tt := range tests {
   324  		reg := &httpmock.Registry{}
   325  		reg.Register(
   326  			httpmock.GraphQL(`query RepositoryInfo\b`),
   327  			httpmock.StringResponse(`
   328  		{ "data": {
   329  				"repository": {
   330  				"description": "social distancing"
   331  		} } }`))
   332  		reg.Register(
   333  			httpmock.REST("GET", "repos/OWNER/REPO/readme"),
   334  			httpmock.StringResponse(`
   335  		{ "name": "readme.org",
   336  		"content": "IyB0cnVseSBjb29sIHJlYWRtZSBjaGVjayBpdCBvdXQ="}`))
   337  
   338  		opts := &ViewOptions{
   339  			HttpClient: func() (*http.Client, error) {
   340  				return &http.Client{Transport: reg}, nil
   341  			},
   342  			BaseRepo: func() (ghrepo.Interface, error) {
   343  				return ghrepo.New("OWNER", "REPO"), nil
   344  			},
   345  		}
   346  
   347  		io, _, stdout, stderr := iostreams.Test()
   348  
   349  		opts.IO = io
   350  
   351  		t.Run(tt.name, func(t *testing.T) {
   352  			io.SetStdoutTTY(tt.stdoutTTY)
   353  
   354  			if err := viewRun(opts); err != nil {
   355  				t.Errorf("viewRun() error = %v", err)
   356  			}
   357  			assert.Equal(t, tt.wantOut, stdout.String())
   358  			assert.Equal(t, "", stderr.String())
   359  			reg.Verify(t)
   360  		})
   361  	}
   362  }
   363  
   364  func Test_ViewRun_NoReadme(t *testing.T) {
   365  	tests := []struct {
   366  		name      string
   367  		stdoutTTY bool
   368  		wantOut   string
   369  	}{
   370  		{
   371  			name: "tty",
   372  			wantOut: heredoc.Doc(`
   373  			OWNER/REPO
   374  			social distancing
   375  
   376  			This repository does not have a README
   377  
   378  			View this repository on GitHub: https://github.com/OWNER/REPO
   379  			`),
   380  			stdoutTTY: true,
   381  		},
   382  		{
   383  			name: "nontty",
   384  			wantOut: heredoc.Doc(`
   385  			name:	OWNER/REPO
   386  			description:	social distancing
   387  			`),
   388  		},
   389  	}
   390  
   391  	for _, tt := range tests {
   392  		reg := &httpmock.Registry{}
   393  		reg.Register(
   394  			httpmock.GraphQL(`query RepositoryInfo\b`),
   395  			httpmock.StringResponse(`
   396  		{ "data": {
   397  				"repository": {
   398  				"description": "social distancing"
   399  		} } }`))
   400  		reg.Register(
   401  			httpmock.REST("GET", "repos/OWNER/REPO/readme"),
   402  			httpmock.StatusStringResponse(404, `{}`))
   403  
   404  		opts := &ViewOptions{
   405  			HttpClient: func() (*http.Client, error) {
   406  				return &http.Client{Transport: reg}, nil
   407  			},
   408  			BaseRepo: func() (ghrepo.Interface, error) {
   409  				return ghrepo.New("OWNER", "REPO"), nil
   410  			},
   411  		}
   412  
   413  		io, _, stdout, stderr := iostreams.Test()
   414  
   415  		opts.IO = io
   416  
   417  		t.Run(tt.name, func(t *testing.T) {
   418  			io.SetStdoutTTY(tt.stdoutTTY)
   419  
   420  			if err := viewRun(opts); err != nil {
   421  				t.Errorf("viewRun() error = %v", err)
   422  			}
   423  			assert.Equal(t, tt.wantOut, stdout.String())
   424  			assert.Equal(t, "", stderr.String())
   425  			reg.Verify(t)
   426  		})
   427  	}
   428  }
   429  
   430  func Test_ViewRun_NoDescription(t *testing.T) {
   431  	tests := []struct {
   432  		name      string
   433  		stdoutTTY bool
   434  		wantOut   string
   435  	}{
   436  		{
   437  			name: "tty",
   438  			wantOut: heredoc.Doc(`
   439  			OWNER/REPO
   440  			No description provided
   441  
   442  			# truly cool readme check it out
   443  
   444  			View this repository on GitHub: https://github.com/OWNER/REPO
   445  			`),
   446  			stdoutTTY: true,
   447  		},
   448  		{
   449  			name: "nontty",
   450  			wantOut: heredoc.Doc(`
   451  			name:	OWNER/REPO
   452  			description:	
   453  			--
   454  			# truly cool readme check it out
   455  			`),
   456  		},
   457  	}
   458  
   459  	for _, tt := range tests {
   460  		reg := &httpmock.Registry{}
   461  		reg.Register(
   462  			httpmock.GraphQL(`query RepositoryInfo\b`),
   463  			httpmock.StringResponse(`
   464  		{ "data": {
   465  				"repository": {
   466  				"description": ""
   467  		} } }`))
   468  		reg.Register(
   469  			httpmock.REST("GET", "repos/OWNER/REPO/readme"),
   470  			httpmock.StringResponse(`
   471  		{ "name": "readme.org",
   472  		"content": "IyB0cnVseSBjb29sIHJlYWRtZSBjaGVjayBpdCBvdXQ="}`))
   473  
   474  		opts := &ViewOptions{
   475  			HttpClient: func() (*http.Client, error) {
   476  				return &http.Client{Transport: reg}, nil
   477  			},
   478  			BaseRepo: func() (ghrepo.Interface, error) {
   479  				return ghrepo.New("OWNER", "REPO"), nil
   480  			},
   481  		}
   482  
   483  		io, _, stdout, stderr := iostreams.Test()
   484  
   485  		opts.IO = io
   486  
   487  		t.Run(tt.name, func(t *testing.T) {
   488  			io.SetStdoutTTY(tt.stdoutTTY)
   489  
   490  			if err := viewRun(opts); err != nil {
   491  				t.Errorf("viewRun() error = %v", err)
   492  			}
   493  			assert.Equal(t, tt.wantOut, stdout.String())
   494  			assert.Equal(t, "", stderr.String())
   495  			reg.Verify(t)
   496  		})
   497  	}
   498  }
   499  
   500  func Test_ViewRun_WithoutUsername(t *testing.T) {
   501  	reg := &httpmock.Registry{}
   502  	reg.Register(
   503  		httpmock.GraphQL(`query UserCurrent\b`),
   504  		httpmock.StringResponse(`
   505  		{ "data": { "viewer": {
   506  			"login": "OWNER"
   507  		}}}`))
   508  	reg.Register(
   509  		httpmock.GraphQL(`query RepositoryInfo\b`),
   510  		httpmock.StringResponse(`
   511  	{ "data": {
   512  		"repository": {
   513  		"description": "social distancing"
   514  	} } }`))
   515  	reg.Register(
   516  		httpmock.REST("GET", "repos/OWNER/REPO/readme"),
   517  		httpmock.StringResponse(`
   518  	{ "name": "readme.md",
   519  	"content": "IyB0cnVseSBjb29sIHJlYWRtZSBjaGVjayBpdCBvdXQ="}`))
   520  
   521  	io, _, stdout, stderr := iostreams.Test()
   522  	io.SetStdoutTTY(false)
   523  
   524  	opts := &ViewOptions{
   525  		RepoArg: "REPO",
   526  		HttpClient: func() (*http.Client, error) {
   527  			return &http.Client{Transport: reg}, nil
   528  		},
   529  		IO: io,
   530  	}
   531  
   532  	if err := viewRun(opts); err != nil {
   533  		t.Errorf("viewRun() error = %v", err)
   534  	}
   535  
   536  	assert.Equal(t, heredoc.Doc(`
   537  			name:	OWNER/REPO
   538  			description:	social distancing
   539  			--
   540  			# truly cool readme check it out
   541  			`), stdout.String())
   542  	assert.Equal(t, "", stderr.String())
   543  	reg.Verify(t)
   544  }
   545  
   546  func Test_ViewRun_HandlesSpecialCharacters(t *testing.T) {
   547  	tests := []struct {
   548  		name       string
   549  		opts       *ViewOptions
   550  		repoName   string
   551  		stdoutTTY  bool
   552  		wantOut    string
   553  		wantStderr string
   554  		wantErr    bool
   555  	}{
   556  		{
   557  			name: "nontty",
   558  			wantOut: heredoc.Doc(`
   559  				name:	OWNER/REPO
   560  				description:	Some basic special characters " & / < > '
   561  				--
   562  				# < is always > than & ' and "
   563  				`),
   564  		},
   565  		{
   566  			name:      "no args",
   567  			stdoutTTY: true,
   568  			wantOut: heredoc.Doc(`
   569  				OWNER/REPO
   570  				Some basic special characters " & / < > '
   571  
   572  
   573  				  # < is always > than & ' and "                                              
   574  
   575  
   576  
   577  				View this repository on GitHub: https://github.com/OWNER/REPO
   578  			`),
   579  		},
   580  	}
   581  	for _, tt := range tests {
   582  		if tt.opts == nil {
   583  			tt.opts = &ViewOptions{}
   584  		}
   585  
   586  		if tt.repoName == "" {
   587  			tt.repoName = "OWNER/REPO"
   588  		}
   589  
   590  		tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
   591  			repo, _ := ghrepo.FromFullName(tt.repoName)
   592  			return repo, nil
   593  		}
   594  
   595  		reg := &httpmock.Registry{}
   596  		reg.Register(
   597  			httpmock.GraphQL(`query RepositoryInfo\b`),
   598  			httpmock.StringResponse(`
   599  		{ "data": {
   600  			"repository": {
   601  			"description": "Some basic special characters \" & / < > '"
   602  		} } }`))
   603  		reg.Register(
   604  			httpmock.REST("GET", fmt.Sprintf("repos/%s/readme", tt.repoName)),
   605  			httpmock.StringResponse(`
   606  		{ "name": "readme.md",
   607  		"content": "IyA8IGlzIGFsd2F5cyA+IHRoYW4gJiAnIGFuZCAi"}`))
   608  
   609  		tt.opts.HttpClient = func() (*http.Client, error) {
   610  			return &http.Client{Transport: reg}, nil
   611  		}
   612  
   613  		io, _, stdout, stderr := iostreams.Test()
   614  		tt.opts.IO = io
   615  
   616  		t.Run(tt.name, func(t *testing.T) {
   617  			io.SetStdoutTTY(tt.stdoutTTY)
   618  
   619  			if err := viewRun(tt.opts); (err != nil) != tt.wantErr {
   620  				t.Errorf("viewRun() error = %v, wantErr %v", err, tt.wantErr)
   621  			}
   622  			assert.Equal(t, tt.wantStderr, stderr.String())
   623  			assert.Equal(t, tt.wantOut, stdout.String())
   624  			reg.Verify(t)
   625  		})
   626  	}
   627  }