github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/repo/clone/clone_test.go (about)

     1  package clone
     2  
     3  import (
     4  	"net/http"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/ungtb10d/cli/v2/git"
     9  	"github.com/ungtb10d/cli/v2/internal/config"
    10  	"github.com/ungtb10d/cli/v2/internal/run"
    11  	"github.com/ungtb10d/cli/v2/pkg/cmdutil"
    12  	"github.com/ungtb10d/cli/v2/pkg/httpmock"
    13  	"github.com/ungtb10d/cli/v2/pkg/iostreams"
    14  	"github.com/ungtb10d/cli/v2/test"
    15  	"github.com/google/shlex"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestNewCmdClone(t *testing.T) {
    21  	testCases := []struct {
    22  		name     string
    23  		args     string
    24  		wantOpts CloneOptions
    25  		wantErr  string
    26  	}{
    27  		{
    28  			name:    "no arguments",
    29  			args:    "",
    30  			wantErr: "cannot clone: repository argument required",
    31  		},
    32  		{
    33  			name: "repo argument",
    34  			args: "OWNER/REPO",
    35  			wantOpts: CloneOptions{
    36  				Repository: "OWNER/REPO",
    37  				GitArgs:    []string{},
    38  			},
    39  		},
    40  		{
    41  			name: "directory argument",
    42  			args: "OWNER/REPO mydir",
    43  			wantOpts: CloneOptions{
    44  				Repository: "OWNER/REPO",
    45  				GitArgs:    []string{"mydir"},
    46  			},
    47  		},
    48  		{
    49  			name: "git clone arguments",
    50  			args: "OWNER/REPO -- --depth 1 --recurse-submodules",
    51  			wantOpts: CloneOptions{
    52  				Repository: "OWNER/REPO",
    53  				GitArgs:    []string{"--depth", "1", "--recurse-submodules"},
    54  			},
    55  		},
    56  		{
    57  			name:    "unknown argument",
    58  			args:    "OWNER/REPO --depth 1",
    59  			wantErr: "unknown flag: --depth\nSeparate git clone flags with '--'.",
    60  		},
    61  	}
    62  	for _, tt := range testCases {
    63  		t.Run(tt.name, func(t *testing.T) {
    64  			ios, stdin, stdout, stderr := iostreams.Test()
    65  			fac := &cmdutil.Factory{IOStreams: ios}
    66  
    67  			var opts *CloneOptions
    68  			cmd := NewCmdClone(fac, func(co *CloneOptions) error {
    69  				opts = co
    70  				return nil
    71  			})
    72  
    73  			argv, err := shlex.Split(tt.args)
    74  			require.NoError(t, err)
    75  			cmd.SetArgs(argv)
    76  
    77  			cmd.SetIn(stdin)
    78  			cmd.SetOut(stderr)
    79  			cmd.SetErr(stderr)
    80  
    81  			_, err = cmd.ExecuteC()
    82  			if tt.wantErr != "" {
    83  				assert.EqualError(t, err, tt.wantErr)
    84  				return
    85  			} else {
    86  				assert.NoError(t, err)
    87  			}
    88  
    89  			assert.Equal(t, "", stdout.String())
    90  			assert.Equal(t, "", stderr.String())
    91  
    92  			assert.Equal(t, tt.wantOpts.Repository, opts.Repository)
    93  			assert.Equal(t, tt.wantOpts.GitArgs, opts.GitArgs)
    94  		})
    95  	}
    96  }
    97  
    98  func runCloneCommand(httpClient *http.Client, cli string) (*test.CmdOut, error) {
    99  	ios, stdin, stdout, stderr := iostreams.Test()
   100  	fac := &cmdutil.Factory{
   101  		IOStreams: ios,
   102  		HttpClient: func() (*http.Client, error) {
   103  			return httpClient, nil
   104  		},
   105  		Config: func() (config.Config, error) {
   106  			return config.NewBlankConfig(), nil
   107  		},
   108  		GitClient: &git.Client{GitPath: "some/path/git"},
   109  	}
   110  
   111  	cmd := NewCmdClone(fac, nil)
   112  
   113  	argv, err := shlex.Split(cli)
   114  	cmd.SetArgs(argv)
   115  
   116  	cmd.SetIn(stdin)
   117  	cmd.SetOut(stderr)
   118  	cmd.SetErr(stderr)
   119  
   120  	if err != nil {
   121  		panic(err)
   122  	}
   123  
   124  	_, err = cmd.ExecuteC()
   125  
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  
   130  	return &test.CmdOut{OutBuf: stdout, ErrBuf: stderr}, nil
   131  }
   132  
   133  func Test_RepoClone(t *testing.T) {
   134  	tests := []struct {
   135  		name string
   136  		args string
   137  		want string
   138  	}{
   139  		{
   140  			name: "shorthand",
   141  			args: "OWNER/REPO",
   142  			want: "git clone https://github.com/OWNER/REPO.git",
   143  		},
   144  		{
   145  			name: "shorthand with directory",
   146  			args: "OWNER/REPO target_directory",
   147  			want: "git clone https://github.com/OWNER/REPO.git target_directory",
   148  		},
   149  		{
   150  			name: "clone arguments",
   151  			args: "OWNER/REPO -- -o upstream --depth 1",
   152  			want: "git clone -o upstream --depth 1 https://github.com/OWNER/REPO.git",
   153  		},
   154  		{
   155  			name: "clone arguments with directory",
   156  			args: "OWNER/REPO target_directory -- -o upstream --depth 1",
   157  			want: "git clone -o upstream --depth 1 https://github.com/OWNER/REPO.git target_directory",
   158  		},
   159  		{
   160  			name: "HTTPS URL",
   161  			args: "https://github.com/OWNER/REPO",
   162  			want: "git clone https://github.com/OWNER/REPO.git",
   163  		},
   164  		{
   165  			name: "SSH URL",
   166  			args: "git@github.com:OWNER/REPO.git",
   167  			want: "git clone git@github.com:OWNER/REPO.git",
   168  		},
   169  		{
   170  			name: "Non-canonical capitalization",
   171  			args: "Owner/Repo",
   172  			want: "git clone https://github.com/OWNER/REPO.git",
   173  		},
   174  		{
   175  			name: "clone wiki",
   176  			args: "Owner/Repo.wiki",
   177  			want: "git clone https://github.com/OWNER/REPO.wiki.git",
   178  		},
   179  		{
   180  			name: "wiki URL",
   181  			args: "https://github.com/owner/repo.wiki",
   182  			want: "git clone https://github.com/OWNER/REPO.wiki.git",
   183  		},
   184  	}
   185  	for _, tt := range tests {
   186  		t.Run(tt.name, func(t *testing.T) {
   187  			reg := &httpmock.Registry{}
   188  			defer reg.Verify(t)
   189  			reg.Register(
   190  				httpmock.GraphQL(`query RepositoryInfo\b`),
   191  				httpmock.StringResponse(`
   192  				{ "data": { "repository": {
   193  					"name": "REPO",
   194  					"owner": {
   195  						"login": "OWNER"
   196  					},
   197  					"hasWikiEnabled": true
   198  				} } }
   199  				`))
   200  
   201  			httpClient := &http.Client{Transport: reg}
   202  
   203  			cs, restore := run.Stub()
   204  			defer restore(t)
   205  			cs.Register(`git clone`, 0, "", func(s []string) {
   206  				assert.Equal(t, tt.want, strings.Join(s, " "))
   207  			})
   208  
   209  			output, err := runCloneCommand(httpClient, tt.args)
   210  			if err != nil {
   211  				t.Fatalf("error running command `repo clone`: %v", err)
   212  			}
   213  
   214  			assert.Equal(t, "", output.String())
   215  			assert.Equal(t, "", output.Stderr())
   216  		})
   217  	}
   218  }
   219  
   220  func Test_RepoClone_hasParent(t *testing.T) {
   221  	reg := &httpmock.Registry{}
   222  	reg.Register(
   223  		httpmock.GraphQL(`query RepositoryInfo\b`),
   224  		httpmock.StringResponse(`
   225  				{ "data": { "repository": {
   226  					"name": "REPO",
   227  					"owner": {
   228  						"login": "OWNER"
   229  					},
   230  					"parent": {
   231  						"name": "ORIG",
   232  						"owner": {
   233  							"login": "hubot"
   234  						},
   235  						"defaultBranchRef": {
   236  							"name": "trunk"
   237  						}
   238  					}
   239  				} } }
   240  				`))
   241  
   242  	httpClient := &http.Client{Transport: reg}
   243  
   244  	cs, cmdTeardown := run.Stub()
   245  	defer cmdTeardown(t)
   246  
   247  	cs.Register(`git clone https://github.com/OWNER/REPO.git`, 0, "")
   248  	cs.Register(`git -C REPO remote add -t trunk -f upstream https://github.com/hubot/ORIG.git`, 0, "")
   249  
   250  	_, err := runCloneCommand(httpClient, "OWNER/REPO")
   251  	if err != nil {
   252  		t.Fatalf("error running command `repo clone`: %v", err)
   253  	}
   254  }
   255  
   256  func Test_RepoClone_hasParent_upstreamRemoteName(t *testing.T) {
   257  	reg := &httpmock.Registry{}
   258  	reg.Register(
   259  		httpmock.GraphQL(`query RepositoryInfo\b`),
   260  		httpmock.StringResponse(`
   261  				{ "data": { "repository": {
   262  					"name": "REPO",
   263  					"owner": {
   264  						"login": "OWNER"
   265  					},
   266  					"parent": {
   267  						"name": "ORIG",
   268  						"owner": {
   269  							"login": "hubot"
   270  						},
   271  						"defaultBranchRef": {
   272  							"name": "trunk"
   273  						}
   274  					}
   275  				} } }
   276  				`))
   277  
   278  	httpClient := &http.Client{Transport: reg}
   279  
   280  	cs, cmdTeardown := run.Stub()
   281  	defer cmdTeardown(t)
   282  
   283  	cs.Register(`git clone https://github.com/OWNER/REPO.git`, 0, "")
   284  	cs.Register(`git -C REPO remote add -t trunk -f test https://github.com/hubot/ORIG.git`, 0, "")
   285  
   286  	_, err := runCloneCommand(httpClient, "OWNER/REPO --upstream-remote-name test")
   287  	if err != nil {
   288  		t.Fatalf("error running command `repo clone`: %v", err)
   289  	}
   290  }
   291  
   292  func Test_RepoClone_withoutUsername(t *testing.T) {
   293  	reg := &httpmock.Registry{}
   294  	defer reg.Verify(t)
   295  	reg.Register(
   296  		httpmock.GraphQL(`query UserCurrent\b`),
   297  		httpmock.StringResponse(`
   298  		{ "data": { "viewer": {
   299  			"login": "OWNER"
   300  		}}}`))
   301  	reg.Register(
   302  		httpmock.GraphQL(`query RepositoryInfo\b`),
   303  		httpmock.StringResponse(`
   304  				{ "data": { "repository": {
   305  					"name": "REPO",
   306  					"owner": {
   307  						"login": "OWNER"
   308  					}
   309  				} } }
   310  				`))
   311  
   312  	httpClient := &http.Client{Transport: reg}
   313  
   314  	cs, restore := run.Stub()
   315  	defer restore(t)
   316  	cs.Register(`git clone https://github\.com/OWNER/REPO\.git`, 0, "")
   317  
   318  	output, err := runCloneCommand(httpClient, "REPO")
   319  	if err != nil {
   320  		t.Fatalf("error running command `repo clone`: %v", err)
   321  	}
   322  
   323  	assert.Equal(t, "", output.String())
   324  	assert.Equal(t, "", output.Stderr())
   325  }