github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/gist/list/list_test.go (about)

     1  package list
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"net/http"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/MakeNowJust/heredoc"
    11  	"github.com/ungtb10d/cli/v2/internal/config"
    12  	"github.com/ungtb10d/cli/v2/pkg/cmdutil"
    13  	"github.com/ungtb10d/cli/v2/pkg/httpmock"
    14  	"github.com/ungtb10d/cli/v2/pkg/iostreams"
    15  	"github.com/google/shlex"
    16  	"github.com/stretchr/testify/assert"
    17  )
    18  
    19  func TestNewCmdList(t *testing.T) {
    20  	tests := []struct {
    21  		name  string
    22  		cli   string
    23  		wants ListOptions
    24  	}{
    25  		{
    26  			name: "no arguments",
    27  			wants: ListOptions{
    28  				Limit:      10,
    29  				Visibility: "all",
    30  			},
    31  		},
    32  		{
    33  			name: "public",
    34  			cli:  "--public",
    35  			wants: ListOptions{
    36  				Limit:      10,
    37  				Visibility: "public",
    38  			},
    39  		},
    40  		{
    41  			name: "secret",
    42  			cli:  "--secret",
    43  			wants: ListOptions{
    44  				Limit:      10,
    45  				Visibility: "secret",
    46  			},
    47  		},
    48  		{
    49  			name: "secret with explicit false value",
    50  			cli:  "--secret=false",
    51  			wants: ListOptions{
    52  				Limit:      10,
    53  				Visibility: "all",
    54  			},
    55  		},
    56  		{
    57  			name: "public and secret",
    58  			cli:  "--secret --public",
    59  			wants: ListOptions{
    60  				Limit:      10,
    61  				Visibility: "secret",
    62  			},
    63  		},
    64  		{
    65  			name: "limit",
    66  			cli:  "--limit 30",
    67  			wants: ListOptions{
    68  				Limit:      30,
    69  				Visibility: "all",
    70  			},
    71  		},
    72  	}
    73  
    74  	for _, tt := range tests {
    75  		t.Run(tt.name, func(t *testing.T) {
    76  			f := &cmdutil.Factory{}
    77  
    78  			argv, err := shlex.Split(tt.cli)
    79  			assert.NoError(t, err)
    80  
    81  			var gotOpts *ListOptions
    82  			cmd := NewCmdList(f, func(opts *ListOptions) error {
    83  				gotOpts = opts
    84  				return nil
    85  			})
    86  			cmd.SetArgs(argv)
    87  			cmd.SetIn(&bytes.Buffer{})
    88  			cmd.SetOut(&bytes.Buffer{})
    89  			cmd.SetErr(&bytes.Buffer{})
    90  
    91  			_, err = cmd.ExecuteC()
    92  			assert.NoError(t, err)
    93  
    94  			assert.Equal(t, tt.wants.Visibility, gotOpts.Visibility)
    95  			assert.Equal(t, tt.wants.Limit, gotOpts.Limit)
    96  		})
    97  	}
    98  }
    99  
   100  func Test_listRun(t *testing.T) {
   101  	const query = `query GistList\b`
   102  	sixHours, _ := time.ParseDuration("6h")
   103  	sixHoursAgo := time.Now().Add(-sixHours)
   104  	absTime, _ := time.Parse(time.RFC3339, "2020-07-30T15:24:28Z")
   105  
   106  	tests := []struct {
   107  		name    string
   108  		opts    *ListOptions
   109  		wantErr bool
   110  		wantOut string
   111  		stubs   func(*httpmock.Registry)
   112  		nontty  bool
   113  	}{
   114  		{
   115  			name: "no gists",
   116  			opts: &ListOptions{},
   117  			stubs: func(reg *httpmock.Registry) {
   118  				reg.Register(
   119  					httpmock.GraphQL(query),
   120  					httpmock.StringResponse(`{ "data": { "viewer": {
   121  						"gists": { "nodes": [] }
   122  					} } }`))
   123  			},
   124  			wantErr: true,
   125  		},
   126  		{
   127  			name: "default behavior",
   128  			opts: &ListOptions{},
   129  			stubs: func(reg *httpmock.Registry) {
   130  				reg.Register(
   131  					httpmock.GraphQL(query),
   132  					httpmock.StringResponse(fmt.Sprintf(
   133  						`{ "data": { "viewer": { "gists": { "nodes": [
   134  							{
   135  								"name": "1234567890",
   136  								"files": [{ "name": "cool.txt" }],
   137  								"description": "",
   138  								"updatedAt": "%[1]v",
   139  								"isPublic": true
   140  							},
   141  							{
   142  								"name": "4567890123",
   143  								"files": [{ "name": "gistfile0.txt" }],
   144  								"description": "",
   145  								"updatedAt": "%[1]v",
   146  								"isPublic": true
   147  							},
   148  							{
   149  								"name": "2345678901",
   150  								"files": [
   151  									{ "name": "gistfile0.txt" },
   152  									{ "name": "gistfile1.txt" }
   153  								],
   154  								"description": "tea leaves thwart those who court catastrophe",
   155  								"updatedAt": "%[1]v",
   156  								"isPublic": false
   157  							},
   158  							{
   159  								"name": "3456789012",
   160  								"files": [
   161  									{ "name": "gistfile0.txt" },
   162  									{ "name": "gistfile1.txt" },
   163  									{ "name": "gistfile2.txt" },
   164  									{ "name": "gistfile3.txt" },
   165  									{ "name": "gistfile4.txt" },
   166  									{ "name": "gistfile5.txt" },
   167  									{ "name": "gistfile6.txt" },
   168  									{ "name": "gistfile7.txt" },
   169  									{ "name": "gistfile9.txt" },
   170  									{ "name": "gistfile10.txt" },
   171  									{ "name": "gistfile11.txt" }
   172  								],
   173  								"description": "short desc",
   174  								"updatedAt": "%[1]v",
   175  								"isPublic": false
   176  							}
   177  						] } } } }`,
   178  						sixHoursAgo.Format(time.RFC3339),
   179  					)),
   180  				)
   181  			},
   182  			wantOut: heredoc.Doc(`
   183  				1234567890  cool.txt                         1 file    public  about 6 hours ago
   184  				4567890123                                   1 file    public  about 6 hours ago
   185  				2345678901  tea leaves thwart those who ...  2 files   secret  about 6 hours ago
   186  				3456789012  short desc                       11 files  secret  about 6 hours ago
   187  			`),
   188  		},
   189  		{
   190  			name: "with public filter",
   191  			opts: &ListOptions{Visibility: "public"},
   192  			stubs: func(reg *httpmock.Registry) {
   193  				reg.Register(
   194  					httpmock.GraphQL(query),
   195  					httpmock.StringResponse(fmt.Sprintf(
   196  						`{ "data": { "viewer": { "gists": { "nodes": [
   197  							{
   198  								"name": "1234567890",
   199  								"files": [{ "name": "cool.txt" }],
   200  								"description": "",
   201  								"updatedAt": "%[1]v",
   202  								"isPublic": true
   203  							},
   204  							{
   205  								"name": "4567890123",
   206  								"files": [{ "name": "gistfile0.txt" }],
   207  								"description": "",
   208  								"updatedAt": "%[1]v",
   209  								"isPublic": true
   210  							}
   211  						] } } } }`,
   212  						sixHoursAgo.Format(time.RFC3339),
   213  					)),
   214  				)
   215  			},
   216  			wantOut: heredoc.Doc(`
   217  				1234567890  cool.txt  1 file  public  about 6 hours ago
   218  				4567890123            1 file  public  about 6 hours ago
   219  			`),
   220  		},
   221  		{
   222  			name: "with secret filter",
   223  			opts: &ListOptions{Visibility: "secret"},
   224  			stubs: func(reg *httpmock.Registry) {
   225  				reg.Register(
   226  					httpmock.GraphQL(query),
   227  					httpmock.StringResponse(fmt.Sprintf(
   228  						`{ "data": { "viewer": { "gists": { "nodes": [
   229  							{
   230  								"name": "2345678901",
   231  								"files": [
   232  									{ "name": "gistfile0.txt" },
   233  									{ "name": "gistfile1.txt" }
   234  								],
   235  								"description": "tea leaves thwart those who court catastrophe",
   236  								"updatedAt": "%[1]v",
   237  								"isPublic": false
   238  							},
   239  							{
   240  								"name": "3456789012",
   241  								"files": [
   242  									{ "name": "gistfile0.txt" },
   243  									{ "name": "gistfile1.txt" },
   244  									{ "name": "gistfile2.txt" },
   245  									{ "name": "gistfile3.txt" },
   246  									{ "name": "gistfile4.txt" },
   247  									{ "name": "gistfile5.txt" },
   248  									{ "name": "gistfile6.txt" },
   249  									{ "name": "gistfile7.txt" },
   250  									{ "name": "gistfile9.txt" },
   251  									{ "name": "gistfile10.txt" },
   252  									{ "name": "gistfile11.txt" }
   253  								],
   254  								"description": "short desc",
   255  								"updatedAt": "%[1]v",
   256  								"isPublic": false
   257  							}
   258  						] } } } }`,
   259  						sixHoursAgo.Format(time.RFC3339),
   260  					)),
   261  				)
   262  			},
   263  			wantOut: heredoc.Doc(`
   264  				2345678901  tea leaves thwart those who ...  2 files   secret  about 6 hours ago
   265  				3456789012  short desc                       11 files  secret  about 6 hours ago
   266  			`),
   267  		},
   268  		{
   269  			name: "with limit",
   270  			opts: &ListOptions{Limit: 1},
   271  			stubs: func(reg *httpmock.Registry) {
   272  				reg.Register(
   273  					httpmock.GraphQL(query),
   274  					httpmock.StringResponse(fmt.Sprintf(
   275  						`{ "data": { "viewer": { "gists": { "nodes": [
   276  							{
   277  								"name": "1234567890",
   278  								"files": [{ "name": "cool.txt" }],
   279  								"description": "",
   280  								"updatedAt": "%v",
   281  								"isPublic": true
   282  							}
   283  						] } } } }`,
   284  						sixHoursAgo.Format(time.RFC3339),
   285  					)),
   286  				)
   287  			},
   288  			wantOut: "1234567890  cool.txt  1 file  public  about 6 hours ago\n",
   289  		},
   290  		{
   291  			name: "nontty output",
   292  			opts: &ListOptions{},
   293  			stubs: func(reg *httpmock.Registry) {
   294  				reg.Register(
   295  					httpmock.GraphQL(query),
   296  					httpmock.StringResponse(fmt.Sprintf(
   297  						`{ "data": { "viewer": { "gists": { "nodes": [
   298  							{
   299  								"name": "1234567890",
   300  								"files": [{ "name": "cool.txt" }],
   301  								"description": "",
   302  								"updatedAt": "%[1]v",
   303  								"isPublic": true
   304  							},
   305  							{
   306  								"name": "4567890123",
   307  								"files": [{ "name": "gistfile0.txt" }],
   308  								"description": "",
   309  								"updatedAt": "%[1]v",
   310  								"isPublic": true
   311  							},
   312  							{
   313  								"name": "2345678901",
   314  								"files": [
   315  									{ "name": "gistfile0.txt" },
   316  									{ "name": "gistfile1.txt" }
   317  								],
   318  								"description": "tea leaves thwart those who court catastrophe",
   319  								"updatedAt": "%[1]v",
   320  								"isPublic": false
   321  							},
   322  							{
   323  								"name": "3456789012",
   324  								"files": [
   325  									{ "name": "gistfile0.txt" },
   326  									{ "name": "gistfile1.txt" },
   327  									{ "name": "gistfile2.txt" },
   328  									{ "name": "gistfile3.txt" },
   329  									{ "name": "gistfile4.txt" },
   330  									{ "name": "gistfile5.txt" },
   331  									{ "name": "gistfile6.txt" },
   332  									{ "name": "gistfile7.txt" },
   333  									{ "name": "gistfile9.txt" },
   334  									{ "name": "gistfile10.txt" },
   335  									{ "name": "gistfile11.txt" }
   336  								],
   337  								"description": "short desc",
   338  								"updatedAt": "%[1]v",
   339  								"isPublic": false
   340  							}
   341  						] } } } }`,
   342  						absTime.Format(time.RFC3339),
   343  					)),
   344  				)
   345  			},
   346  			wantOut: heredoc.Doc(`
   347  				1234567890	cool.txt	1 file	public	2020-07-30T15:24:28Z
   348  				4567890123		1 file	public	2020-07-30T15:24:28Z
   349  				2345678901	tea leaves thwart those who court catastrophe	2 files	secret	2020-07-30T15:24:28Z
   350  				3456789012	short desc	11 files	secret	2020-07-30T15:24:28Z
   351  			`),
   352  			nontty: true,
   353  		},
   354  	}
   355  
   356  	for _, tt := range tests {
   357  		reg := &httpmock.Registry{}
   358  		tt.stubs(reg)
   359  
   360  		tt.opts.HttpClient = func() (*http.Client, error) {
   361  			return &http.Client{Transport: reg}, nil
   362  		}
   363  
   364  		tt.opts.Config = func() (config.Config, error) {
   365  			return config.NewBlankConfig(), nil
   366  		}
   367  
   368  		ios, _, stdout, _ := iostreams.Test()
   369  		ios.SetStdoutTTY(!tt.nontty)
   370  		tt.opts.IO = ios
   371  
   372  		if tt.opts.Limit == 0 {
   373  			tt.opts.Limit = 10
   374  		}
   375  
   376  		if tt.opts.Visibility == "" {
   377  			tt.opts.Visibility = "all"
   378  		}
   379  		t.Run(tt.name, func(t *testing.T) {
   380  			err := listRun(tt.opts)
   381  			if tt.wantErr {
   382  				assert.Error(t, err)
   383  			} else {
   384  				assert.NoError(t, err)
   385  			}
   386  
   387  			assert.Equal(t, tt.wantOut, stdout.String())
   388  			reg.Verify(t)
   389  		})
   390  	}
   391  }