github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/alias/set/set_test.go (about) 1 package set 2 3 import ( 4 "bytes" 5 "io" 6 "testing" 7 8 "github.com/MakeNowJust/heredoc" 9 "github.com/ungtb10d/cli/v2/internal/config" 10 "github.com/ungtb10d/cli/v2/pkg/cmdutil" 11 "github.com/ungtb10d/cli/v2/pkg/extensions" 12 "github.com/ungtb10d/cli/v2/pkg/iostreams" 13 "github.com/ungtb10d/cli/v2/test" 14 "github.com/google/shlex" 15 "github.com/spf13/cobra" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 func runCommand(cfg config.Config, isTTY bool, cli string, in string) (*test.CmdOut, error) { 21 ios, stdin, stdout, stderr := iostreams.Test() 22 ios.SetStdoutTTY(isTTY) 23 ios.SetStdinTTY(isTTY) 24 ios.SetStderrTTY(isTTY) 25 stdin.WriteString(in) 26 27 factory := &cmdutil.Factory{ 28 IOStreams: ios, 29 Config: func() (config.Config, error) { 30 return cfg, nil 31 }, 32 ExtensionManager: &extensions.ExtensionManagerMock{ 33 ListFunc: func() []extensions.Extension { 34 return []extensions.Extension{} 35 }, 36 }, 37 } 38 39 cmd := NewCmdSet(factory, nil) 40 41 // fake command nesting structure needed for validCommand 42 rootCmd := &cobra.Command{} 43 rootCmd.AddCommand(cmd) 44 prCmd := &cobra.Command{Use: "pr"} 45 prCmd.AddCommand(&cobra.Command{Use: "checkout"}) 46 prCmd.AddCommand(&cobra.Command{Use: "status"}) 47 rootCmd.AddCommand(prCmd) 48 issueCmd := &cobra.Command{Use: "issue"} 49 issueCmd.AddCommand(&cobra.Command{Use: "list"}) 50 rootCmd.AddCommand(issueCmd) 51 apiCmd := &cobra.Command{Use: "api"} 52 apiCmd.AddCommand(&cobra.Command{Use: "graphql"}) 53 rootCmd.AddCommand(apiCmd) 54 55 argv, err := shlex.Split("set " + cli) 56 if err != nil { 57 return nil, err 58 } 59 rootCmd.SetArgs(argv) 60 61 rootCmd.SetIn(stdin) 62 rootCmd.SetOut(io.Discard) 63 rootCmd.SetErr(io.Discard) 64 65 _, err = rootCmd.ExecuteC() 66 return &test.CmdOut{ 67 OutBuf: stdout, 68 ErrBuf: stderr, 69 }, err 70 } 71 72 func TestAliasSet_gh_command(t *testing.T) { 73 cfg := config.NewFromString(``) 74 75 _, err := runCommand(cfg, true, "pr 'pr status'", "") 76 assert.EqualError(t, err, `could not create alias: "pr" is already a gh command`) 77 } 78 79 func TestAliasSet_empty_aliases(t *testing.T) { 80 readConfigs := config.StubWriteConfig(t) 81 82 cfg := config.NewFromString(heredoc.Doc(` 83 aliases: 84 editor: vim 85 `)) 86 87 output, err := runCommand(cfg, true, "co 'pr checkout'", "") 88 89 if err != nil { 90 t.Fatalf("unexpected error: %s", err) 91 } 92 93 mainBuf := bytes.Buffer{} 94 readConfigs(&mainBuf, io.Discard) 95 96 //nolint:staticcheck // prefer exact matchers over ExpectLines 97 test.ExpectLines(t, output.Stderr(), "Added alias") 98 //nolint:staticcheck // prefer exact matchers over ExpectLines 99 test.ExpectLines(t, output.String(), "") 100 101 expected := `aliases: 102 co: pr checkout 103 editor: vim 104 ` 105 assert.Equal(t, expected, mainBuf.String()) 106 } 107 108 func TestAliasSet_existing_alias(t *testing.T) { 109 _ = config.StubWriteConfig(t) 110 111 cfg := config.NewFromString(heredoc.Doc(` 112 aliases: 113 co: pr checkout 114 `)) 115 116 output, err := runCommand(cfg, true, "co 'pr checkout -Rcool/repo'", "") 117 require.NoError(t, err) 118 119 //nolint:staticcheck // prefer exact matchers over ExpectLines 120 test.ExpectLines(t, output.Stderr(), "Changed alias.*co.*from.*pr checkout.*to.*pr checkout -Rcool/repo") 121 } 122 123 func TestAliasSet_space_args(t *testing.T) { 124 readConfigs := config.StubWriteConfig(t) 125 126 cfg := config.NewFromString(``) 127 128 output, err := runCommand(cfg, true, `il 'issue list -l "cool story"'`, "") 129 require.NoError(t, err) 130 131 mainBuf := bytes.Buffer{} 132 readConfigs(&mainBuf, io.Discard) 133 134 //nolint:staticcheck // prefer exact matchers over ExpectLines 135 test.ExpectLines(t, output.Stderr(), `Adding alias for.*il.*issue list -l "cool story"`) 136 137 //nolint:staticcheck // prefer exact matchers over ExpectLines 138 test.ExpectLines(t, mainBuf.String(), `il: issue list -l "cool story"`) 139 } 140 141 func TestAliasSet_arg_processing(t *testing.T) { 142 readConfigs := config.StubWriteConfig(t) 143 144 cases := []struct { 145 Cmd string 146 ExpectedOutputLine string 147 ExpectedConfigLine string 148 }{ 149 {`il "issue list"`, "- Adding alias for.*il.*issue list", "il: issue list"}, 150 151 {`iz 'issue list'`, "- Adding alias for.*iz.*issue list", "iz: issue list"}, 152 153 {`ii 'issue list --author="$1" --label="$2"'`, 154 `- Adding alias for.*ii.*issue list --author="\$1" --label="\$2"`, 155 `ii: issue list --author="\$1" --label="\$2"`}, 156 157 {`ix "issue list --author='\$1' --label='\$2'"`, 158 `- Adding alias for.*ix.*issue list --author='\$1' --label='\$2'`, 159 `ix: issue list --author='\$1' --label='\$2'`}, 160 } 161 162 for _, c := range cases { 163 t.Run(c.Cmd, func(t *testing.T) { 164 cfg := config.NewFromString(``) 165 166 output, err := runCommand(cfg, true, c.Cmd, "") 167 if err != nil { 168 t.Fatalf("got unexpected error running %s: %s", c.Cmd, err) 169 } 170 171 mainBuf := bytes.Buffer{} 172 readConfigs(&mainBuf, io.Discard) 173 174 //nolint:staticcheck // prefer exact matchers over ExpectLines 175 test.ExpectLines(t, output.Stderr(), c.ExpectedOutputLine) 176 //nolint:staticcheck // prefer exact matchers over ExpectLines 177 test.ExpectLines(t, mainBuf.String(), c.ExpectedConfigLine) 178 }) 179 } 180 } 181 182 func TestAliasSet_init_alias_cfg(t *testing.T) { 183 readConfigs := config.StubWriteConfig(t) 184 185 cfg := config.NewFromString(heredoc.Doc(` 186 editor: vim 187 `)) 188 189 output, err := runCommand(cfg, true, "diff 'pr diff'", "") 190 require.NoError(t, err) 191 192 mainBuf := bytes.Buffer{} 193 readConfigs(&mainBuf, io.Discard) 194 195 expected := `editor: vim 196 aliases: 197 diff: pr diff 198 ` 199 200 //nolint:staticcheck // prefer exact matchers over ExpectLines 201 test.ExpectLines(t, output.Stderr(), "Adding alias for.*diff.*pr diff", "Added alias.") 202 assert.Equal(t, expected, mainBuf.String()) 203 } 204 205 func TestAliasSet_existing_aliases(t *testing.T) { 206 readConfigs := config.StubWriteConfig(t) 207 208 cfg := config.NewFromString(heredoc.Doc(` 209 aliases: 210 foo: bar 211 `)) 212 213 output, err := runCommand(cfg, true, "view 'pr view'", "") 214 require.NoError(t, err) 215 216 mainBuf := bytes.Buffer{} 217 readConfigs(&mainBuf, io.Discard) 218 219 expected := `aliases: 220 foo: bar 221 view: pr view 222 ` 223 224 //nolint:staticcheck // prefer exact matchers over ExpectLines 225 test.ExpectLines(t, output.Stderr(), "Adding alias for.*view.*pr view", "Added alias.") 226 assert.Equal(t, expected, mainBuf.String()) 227 228 } 229 230 func TestAliasSet_invalid_command(t *testing.T) { 231 cfg := config.NewFromString(``) 232 233 _, err := runCommand(cfg, true, "co 'pe checkout'", "") 234 assert.EqualError(t, err, "could not create alias: pe checkout does not correspond to a gh command") 235 } 236 237 func TestShellAlias_flag(t *testing.T) { 238 readConfigs := config.StubWriteConfig(t) 239 240 cfg := config.NewFromString(``) 241 242 output, err := runCommand(cfg, true, "--shell igrep 'gh issue list | grep'", "") 243 if err != nil { 244 t.Fatalf("unexpected error: %s", err) 245 } 246 247 mainBuf := bytes.Buffer{} 248 readConfigs(&mainBuf, io.Discard) 249 250 //nolint:staticcheck // prefer exact matchers over ExpectLines 251 test.ExpectLines(t, output.Stderr(), "Adding alias for.*igrep") 252 253 expected := `aliases: 254 igrep: '!gh issue list | grep' 255 ` 256 assert.Equal(t, expected, mainBuf.String()) 257 } 258 259 func TestShellAlias_bang(t *testing.T) { 260 readConfigs := config.StubWriteConfig(t) 261 262 cfg := config.NewFromString(``) 263 264 output, err := runCommand(cfg, true, "igrep '!gh issue list | grep'", "") 265 require.NoError(t, err) 266 267 mainBuf := bytes.Buffer{} 268 readConfigs(&mainBuf, io.Discard) 269 270 //nolint:staticcheck // prefer exact matchers over ExpectLines 271 test.ExpectLines(t, output.Stderr(), "Adding alias for.*igrep") 272 273 expected := `aliases: 274 igrep: '!gh issue list | grep' 275 ` 276 assert.Equal(t, expected, mainBuf.String()) 277 } 278 279 func TestShellAlias_from_stdin(t *testing.T) { 280 readConfigs := config.StubWriteConfig(t) 281 282 cfg := config.NewFromString(``) 283 284 output, err := runCommand(cfg, true, "users -", `api graphql -F name="$1" -f query=' 285 query ($name: String!) { 286 user(login: $name) { 287 name 288 } 289 }'`) 290 291 require.NoError(t, err) 292 293 mainBuf := bytes.Buffer{} 294 readConfigs(&mainBuf, io.Discard) 295 296 //nolint:staticcheck // prefer exact matchers over ExpectLines 297 test.ExpectLines(t, output.Stderr(), "Adding alias for.*users") 298 299 expected := `aliases: 300 users: |- 301 api graphql -F name="$1" -f query=' 302 query ($name: String!) { 303 user(login: $name) { 304 name 305 } 306 }' 307 ` 308 309 assert.Equal(t, expected, mainBuf.String()) 310 } 311 312 func TestShellAlias_getExpansion(t *testing.T) { 313 tests := []struct { 314 name string 315 want string 316 expansionArg string 317 stdin string 318 }{ 319 { 320 name: "co", 321 want: "pr checkout", 322 expansionArg: "pr checkout", 323 }, 324 { 325 name: "co", 326 want: "pr checkout", 327 expansionArg: "pr checkout", 328 stdin: "api graphql -F name=\"$1\"", 329 }, 330 { 331 name: "stdin", 332 expansionArg: "-", 333 want: "api graphql -F name=\"$1\"", 334 stdin: "api graphql -F name=\"$1\"", 335 }, 336 } 337 338 for _, tt := range tests { 339 t.Run(tt.name, func(t *testing.T) { 340 ios, stdin, _, _ := iostreams.Test() 341 ios.SetStdinTTY(false) 342 343 _, err := stdin.WriteString(tt.stdin) 344 assert.NoError(t, err) 345 346 expansion, err := getExpansion(&SetOptions{ 347 Expansion: tt.expansionArg, 348 IO: ios, 349 }) 350 assert.NoError(t, err) 351 352 assert.Equal(t, expansion, tt.want) 353 }) 354 } 355 }