1package cmd
2
3import (
4 "io"
5 "testing"
6
7 "github.com/spf13/cobra"
8 "github.com/stretchr/testify/require"
9)
10
11func TestParseBrowseArgs(t *testing.T) {
12 for _, tt := range []struct {
13 name, url, instance string
14 args []string
15 ok bool
16 }{
17 {"normal", "", "", nil, true},
18 {"named", "", "work", []string{"--instance", "work"}, true},
19 {"url after", "https://example.com", "work", []string{"--instance", "work", "https://example.com"}, true},
20 {"url before", "https://example.com", "work", []string{"https://example.com", "--instance", "work"}, true},
21 {"missing name", "", "", []string{"--instance"}, false},
22 {"empty equals", "", "", []string{"--instance="}, false},
23 {"empty separate", "", "", []string{"--instance", ""}, false},
24 {"flag-like name", "", "", []string{"--instance", "--ephemeral"}, false},
25 {"flag-like profile", "", "", []string{"--profile", "--ephemeral"}, false},
26 {"help", "", "", []string{"--help"}, false},
27 {"unknown", "", "", []string{"--unknown"}, false},
28 {"extra", "", "", []string{"--instance", "work", "a", "b"}, false},
29 } {
30 t.Run(tt.name, func(t *testing.T) {
31 url, instance, ok := ParseBrowseArgs(tt.args)
32 require.Equal(t, tt.url, url)
33 require.Equal(t, tt.instance, instance)
34 require.Equal(t, tt.ok, ok)
35 })
36 }
37 require.NotNil(t, browseCmd.Flags().Lookup("instance"))
38 require.NotNil(t, browseCmd.Flags().Lookup("profile"))
39 require.NotNil(t, browseCmd.Flags().Lookup("ephemeral"))
40}
41
42func TestParseBrowseLaunchArgsProfiles(t *testing.T) {
43 parsed, ok := ParseBrowseLaunchArgs([]string{"--instance", "scratch", "https://example.com"})
44 require.True(t, ok)
45 require.Equal(t, BrowseArgs{URL: "https://example.com", Instance: "scratch"}, parsed)
46
47 parsed, ok = ParseBrowseLaunchArgs([]string{"--instance", "work", "--profile", "work"})
48 require.True(t, ok)
49 require.Equal(t, BrowseArgs{Instance: "work", Profile: "work"}, parsed)
50
51 parsed, ok = ParseBrowseLaunchArgs([]string{"--instance", "private", "--ephemeral"})
52 require.True(t, ok)
53 require.Equal(t, BrowseArgs{Instance: "private", Ephemeral: true}, parsed)
54
55 _, ok = ParseBrowseLaunchArgs([]string{"--profile", "work", "--ephemeral"})
56 require.False(t, ok)
57
58 _, ok = ParseBrowseLaunchArgs([]string{"--profile", "--ephemeral"})
59 require.False(t, ok, "a flag-like profile must not be treated as a profile name")
60
61 _, ok = ParseBrowseLaunchArgs([]string{"--instance", "--ephemeral"})
62 require.False(t, ok, "a flag-like instance must not be treated as an instance name")
63}
64
65// browsePreRunEError exercises the real browse PreRunE through Cobra flag
66// parsing, which is the fallback path main takes when early launch parsing
67// rejects the arguments.
68func browsePreRunEError(t *testing.T, args []string) error {
69 t.Helper()
70 cmd := &cobra.Command{
71 Use: "browse",
72 Args: cobra.MaximumNArgs(1),
73 SilenceErrors: true,
74 SilenceUsage: true,
75 PreRunE: browseCmd.PreRunE,
76 Run: func(*cobra.Command, []string) {},
77 }
78 cmd.Flags().AddFlagSet(browseFlags())
79 cmd.SetOut(io.Discard)
80 cmd.SetErr(io.Discard)
81 cmd.SetArgs(args)
82 return cmd.Execute()
83}
84
85func TestBrowseCommandPreRunERejectsFlagLikeValues(t *testing.T) {
86 require.Error(t, browsePreRunEError(t, []string{"--instance", "--ephemeral"}))
87 require.Error(t, browsePreRunEError(t, []string{"--profile", "--ephemeral"}))
88 require.Error(t, browsePreRunEError(t, []string{"--instance", ""}))
89 require.Error(t, browsePreRunEError(t, []string{"--profile", ""}))
90
91 require.NoError(t, browsePreRunEError(t, []string{"--instance", "work"}))
92 require.NoError(t, browsePreRunEError(t, []string{"--instance", "private", "--ephemeral"}))
93 require.NoError(t, browsePreRunEError(t, []string{"--profile", "work"}))
94}