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