github.com/cli/cli@v1.14.1-0.20210902173923-1af6a669e342/pkg/cmd/repo/list/list_test.go (about)

     1  package list
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/MakeNowJust/heredoc"
    11  	"github.com/cli/cli/internal/config"
    12  	"github.com/cli/cli/pkg/cmdutil"
    13  	"github.com/cli/cli/pkg/httpmock"
    14  	"github.com/cli/cli/pkg/iostreams"
    15  	"github.com/cli/cli/test"
    16  	"github.com/google/shlex"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  func TestNewCmdList(t *testing.T) {
    22  	tests := []struct {
    23  		name     string
    24  		cli      string
    25  		wants    ListOptions
    26  		wantsErr string
    27  	}{
    28  		{
    29  			name: "no arguments",
    30  			cli:  "",
    31  			wants: ListOptions{
    32  				Limit:       30,
    33  				Owner:       "",
    34  				Visibility:  "",
    35  				Fork:        false,
    36  				Source:      false,
    37  				Language:    "",
    38  				Topic:       "",
    39  				Archived:    false,
    40  				NonArchived: false,
    41  			},
    42  		},
    43  		{
    44  			name: "with owner",
    45  			cli:  "monalisa",
    46  			wants: ListOptions{
    47  				Limit:       30,
    48  				Owner:       "monalisa",
    49  				Visibility:  "",
    50  				Fork:        false,
    51  				Source:      false,
    52  				Language:    "",
    53  				Topic:       "",
    54  				Archived:    false,
    55  				NonArchived: false,
    56  			},
    57  		},
    58  		{
    59  			name: "with limit",
    60  			cli:  "-L 101",
    61  			wants: ListOptions{
    62  				Limit:       101,
    63  				Owner:       "",
    64  				Visibility:  "",
    65  				Fork:        false,
    66  				Source:      false,
    67  				Language:    "",
    68  				Topic:       "",
    69  				Archived:    false,
    70  				NonArchived: false,
    71  			},
    72  		},
    73  		{
    74  			name: "only public",
    75  			cli:  "--public",
    76  			wants: ListOptions{
    77  				Limit:       30,
    78  				Owner:       "",
    79  				Visibility:  "public",
    80  				Fork:        false,
    81  				Source:      false,
    82  				Language:    "",
    83  				Topic:       "",
    84  				Archived:    false,
    85  				NonArchived: false,
    86  			},
    87  		},
    88  		{
    89  			name: "only private",
    90  			cli:  "--private",
    91  			wants: ListOptions{
    92  				Limit:       30,
    93  				Owner:       "",
    94  				Visibility:  "private",
    95  				Fork:        false,
    96  				Source:      false,
    97  				Language:    "",
    98  				Topic:       "",
    99  				Archived:    false,
   100  				NonArchived: false,
   101  			},
   102  		},
   103  		{
   104  			name: "only forks",
   105  			cli:  "--fork",
   106  			wants: ListOptions{
   107  				Limit:       30,
   108  				Owner:       "",
   109  				Visibility:  "",
   110  				Fork:        true,
   111  				Source:      false,
   112  				Language:    "",
   113  				Topic:       "",
   114  				Archived:    false,
   115  				NonArchived: false,
   116  			},
   117  		},
   118  		{
   119  			name: "only sources",
   120  			cli:  "--source",
   121  			wants: ListOptions{
   122  				Limit:       30,
   123  				Owner:       "",
   124  				Visibility:  "",
   125  				Fork:        false,
   126  				Source:      true,
   127  				Language:    "",
   128  				Topic:       "",
   129  				Archived:    false,
   130  				NonArchived: false,
   131  			},
   132  		},
   133  		{
   134  			name: "with language",
   135  			cli:  "-l go",
   136  			wants: ListOptions{
   137  				Limit:       30,
   138  				Owner:       "",
   139  				Visibility:  "",
   140  				Fork:        false,
   141  				Source:      false,
   142  				Language:    "go",
   143  				Topic:       "",
   144  				Archived:    false,
   145  				NonArchived: false,
   146  			},
   147  		},
   148  		{
   149  			name: "only archived",
   150  			cli:  "--archived",
   151  			wants: ListOptions{
   152  				Limit:       30,
   153  				Owner:       "",
   154  				Visibility:  "",
   155  				Fork:        false,
   156  				Source:      false,
   157  				Language:    "",
   158  				Topic:       "",
   159  				Archived:    true,
   160  				NonArchived: false,
   161  			},
   162  		},
   163  		{
   164  			name: "only non-archived",
   165  			cli:  "--no-archived",
   166  			wants: ListOptions{
   167  				Limit:       30,
   168  				Owner:       "",
   169  				Visibility:  "",
   170  				Fork:        false,
   171  				Source:      false,
   172  				Language:    "",
   173  				Topic:       "",
   174  				Archived:    false,
   175  				NonArchived: true,
   176  			},
   177  		},
   178  		{
   179  			name: "with topic",
   180  			cli:  "--topic cli",
   181  			wants: ListOptions{
   182  				Limit:       30,
   183  				Owner:       "",
   184  				Visibility:  "",
   185  				Fork:        false,
   186  				Source:      false,
   187  				Language:    "",
   188  				Topic:       "cli",
   189  				Archived:    false,
   190  				NonArchived: false,
   191  			},
   192  		},
   193  		{
   194  			name:     "no public and private",
   195  			cli:      "--public --private",
   196  			wantsErr: "specify only one of `--public` or `--private`",
   197  		},
   198  		{
   199  			name:     "no forks with sources",
   200  			cli:      "--fork --source",
   201  			wantsErr: "specify only one of `--source` or `--fork`",
   202  		},
   203  		{
   204  			name:     "conflicting archived",
   205  			cli:      "--archived --no-archived",
   206  			wantsErr: "specify only one of `--archived` or `--no-archived`",
   207  		},
   208  		{
   209  			name:     "too many arguments",
   210  			cli:      "monalisa hubot",
   211  			wantsErr: "accepts at most 1 arg(s), received 2",
   212  		},
   213  		{
   214  			name:     "invalid limit",
   215  			cli:      "-L 0",
   216  			wantsErr: "invalid limit: 0",
   217  		},
   218  	}
   219  
   220  	for _, tt := range tests {
   221  		t.Run(tt.name, func(t *testing.T) {
   222  			f := &cmdutil.Factory{}
   223  
   224  			argv, err := shlex.Split(tt.cli)
   225  			assert.NoError(t, err)
   226  
   227  			var gotOpts *ListOptions
   228  			cmd := NewCmdList(f, func(opts *ListOptions) error {
   229  				gotOpts = opts
   230  				return nil
   231  			})
   232  			cmd.SetArgs(argv)
   233  			cmd.SetIn(&bytes.Buffer{})
   234  			cmd.SetOut(&bytes.Buffer{})
   235  			cmd.SetErr(&bytes.Buffer{})
   236  
   237  			_, err = cmd.ExecuteC()
   238  			if tt.wantsErr != "" {
   239  				assert.EqualError(t, err, tt.wantsErr)
   240  				return
   241  			}
   242  			require.NoError(t, err)
   243  
   244  			assert.Equal(t, tt.wants.Limit, gotOpts.Limit)
   245  			assert.Equal(t, tt.wants.Owner, gotOpts.Owner)
   246  			assert.Equal(t, tt.wants.Visibility, gotOpts.Visibility)
   247  			assert.Equal(t, tt.wants.Fork, gotOpts.Fork)
   248  			assert.Equal(t, tt.wants.Topic, gotOpts.Topic)
   249  			assert.Equal(t, tt.wants.Source, gotOpts.Source)
   250  			assert.Equal(t, tt.wants.Archived, gotOpts.Archived)
   251  			assert.Equal(t, tt.wants.NonArchived, gotOpts.NonArchived)
   252  		})
   253  	}
   254  }
   255  
   256  func runCommand(rt http.RoundTripper, isTTY bool, cli string) (*test.CmdOut, error) {
   257  	io, _, stdout, stderr := iostreams.Test()
   258  	io.SetStdoutTTY(isTTY)
   259  	io.SetStdinTTY(isTTY)
   260  	io.SetStderrTTY(isTTY)
   261  
   262  	factory := &cmdutil.Factory{
   263  		IOStreams: io,
   264  		HttpClient: func() (*http.Client, error) {
   265  			return &http.Client{Transport: rt}, nil
   266  		},
   267  		Config: func() (config.Config, error) {
   268  			return config.NewBlankConfig(), nil
   269  		},
   270  	}
   271  
   272  	cmd := NewCmdList(factory, nil)
   273  
   274  	argv, err := shlex.Split(cli)
   275  	if err != nil {
   276  		return nil, err
   277  	}
   278  	cmd.SetArgs(argv)
   279  
   280  	cmd.SetIn(&bytes.Buffer{})
   281  	cmd.SetOut(ioutil.Discard)
   282  	cmd.SetErr(ioutil.Discard)
   283  
   284  	_, err = cmd.ExecuteC()
   285  	return &test.CmdOut{
   286  		OutBuf: stdout,
   287  		ErrBuf: stderr,
   288  	}, err
   289  }
   290  
   291  func TestRepoList_nontty(t *testing.T) {
   292  	io, _, stdout, stderr := iostreams.Test()
   293  	io.SetStdoutTTY(false)
   294  	io.SetStdinTTY(false)
   295  	io.SetStderrTTY(false)
   296  
   297  	httpReg := &httpmock.Registry{}
   298  	defer httpReg.Verify(t)
   299  
   300  	httpReg.Register(
   301  		httpmock.GraphQL(`query RepositoryList\b`),
   302  		httpmock.FileResponse("./fixtures/repoList.json"),
   303  	)
   304  
   305  	opts := ListOptions{
   306  		IO: io,
   307  		HttpClient: func() (*http.Client, error) {
   308  			return &http.Client{Transport: httpReg}, nil
   309  		},
   310  		Config: func() (config.Config, error) {
   311  			return config.NewBlankConfig(), nil
   312  		},
   313  		Now: func() time.Time {
   314  			t, _ := time.Parse(time.RFC822, "19 Feb 21 15:00 UTC")
   315  			return t
   316  		},
   317  		Limit: 30,
   318  	}
   319  
   320  	err := listRun(&opts)
   321  	assert.NoError(t, err)
   322  
   323  	assert.Equal(t, "", stderr.String())
   324  
   325  	assert.Equal(t, heredoc.Doc(`
   326  		octocat/hello-world	My first repository	public	2021-02-19T06:34:58Z
   327  		octocat/cli	GitHub CLI	public, fork	2021-02-19T06:06:06Z
   328  		octocat/testing		private	2021-02-11T22:32:05Z
   329  	`), stdout.String())
   330  }
   331  
   332  func TestRepoList_tty(t *testing.T) {
   333  	io, _, stdout, stderr := iostreams.Test()
   334  	io.SetStdoutTTY(true)
   335  	io.SetStdinTTY(true)
   336  	io.SetStderrTTY(true)
   337  
   338  	httpReg := &httpmock.Registry{}
   339  	defer httpReg.Verify(t)
   340  
   341  	httpReg.Register(
   342  		httpmock.GraphQL(`query RepositoryList\b`),
   343  		httpmock.FileResponse("./fixtures/repoList.json"),
   344  	)
   345  
   346  	opts := ListOptions{
   347  		IO: io,
   348  		HttpClient: func() (*http.Client, error) {
   349  			return &http.Client{Transport: httpReg}, nil
   350  		},
   351  		Config: func() (config.Config, error) {
   352  			return config.NewBlankConfig(), nil
   353  		},
   354  		Now: func() time.Time {
   355  			t, _ := time.Parse(time.RFC822, "19 Feb 21 15:00 UTC")
   356  			return t
   357  		},
   358  		Limit: 30,
   359  	}
   360  
   361  	err := listRun(&opts)
   362  	assert.NoError(t, err)
   363  
   364  	assert.Equal(t, "", stderr.String())
   365  
   366  	assert.Equal(t, heredoc.Doc(`
   367  
   368  		Showing 3 of 3 repositories in @octocat
   369  
   370  		octocat/hello-world  My first repository  public        8h
   371  		octocat/cli          GitHub CLI           public, fork  8h
   372  		octocat/testing                           private       7d
   373  	`), stdout.String())
   374  }
   375  
   376  func TestRepoList_filtering(t *testing.T) {
   377  	http := &httpmock.Registry{}
   378  	defer http.Verify(t)
   379  
   380  	http.Register(
   381  		httpmock.GraphQL(`query RepositoryList\b`),
   382  		httpmock.GraphQLQuery(`{}`, func(_ string, params map[string]interface{}) {
   383  			assert.Equal(t, "PRIVATE", params["privacy"])
   384  			assert.Equal(t, float64(2), params["perPage"])
   385  		}),
   386  	)
   387  
   388  	output, err := runCommand(http, true, `--private --limit 2 `)
   389  	if err != nil {
   390  		t.Fatal(err)
   391  	}
   392  
   393  	assert.Equal(t, "", output.Stderr())
   394  	assert.Equal(t, "\nNo results match your search\n\n", output.String())
   395  }