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