Skip to content

Commit 1b56346

Browse files
committed
Add xdg-open fake for macOS tests
1 parent ff71380 commit 1b56346

8 files changed

Lines changed: 142 additions & 54 deletions

File tree

internal/cli/cli.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,29 @@ func getExitCode(err error, defaultCode int) int {
161161
return defaultCode
162162
}
163163

164-
// do not fail on config error in it is help (-h, --help) or --init or completion command.
164+
// do not fail on config error if it is help (-h, --help), --init, completion, or lets self.
165165
func failOnConfigError(root *cobra.Command, current *cobra.Command, rootFlags *flags) bool {
166-
rootCommands := set.NewSet("completion", "help", "self", "lsp", "doc")
167-
return (root.Flags().NFlag() == 0 && !rootCommands.Contains(current.Name())) && !rootFlags.help && !rootFlags.init
166+
return (root.Flags().NFlag() == 0 && !allowsMissingConfig(current)) && !rootFlags.help && !rootFlags.init
167+
}
168+
169+
func allowsMissingConfig(current *cobra.Command) bool {
170+
if current == nil {
171+
return false
172+
}
173+
174+
switch current.Name() {
175+
case "completion", "help":
176+
return true
177+
}
178+
179+
for cmd := current; cmd != nil; cmd = cmd.Parent() {
180+
parent := cmd.Parent()
181+
if cmd.Name() == "self" && parent != nil && parent.Name() == "lets" {
182+
return true
183+
}
184+
}
185+
186+
return false
168187
}
169188

170189
type flags struct {

internal/cli/cli_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package cli
2+
3+
import (
4+
"testing"
5+
6+
cmdpkg "github.com/lets-cli/lets/internal/cmd"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
func TestAllowsMissingConfig(t *testing.T) {
11+
t.Run("help", func(t *testing.T) {
12+
command := &cobra.Command{Use: "help"}
13+
if !allowsMissingConfig(command) {
14+
t.Fatal("expected help to allow missing config")
15+
}
16+
})
17+
18+
t.Run("completion", func(t *testing.T) {
19+
root := cmdpkg.CreateRootCommand("v0.0.0-test", "")
20+
cmdpkg.InitCompletionCmd(root, nil)
21+
22+
command, _, err := root.Find([]string{"completion"})
23+
if err != nil {
24+
t.Fatalf("unexpected error: %v", err)
25+
}
26+
27+
if !allowsMissingConfig(command) {
28+
t.Fatal("expected completion to allow missing config")
29+
}
30+
})
31+
32+
t.Run("self subcommand", func(t *testing.T) {
33+
root := cmdpkg.CreateRootCommand("v0.0.0-test", "")
34+
cmdpkg.InitSelfCmd(root, "v0.0.0-test")
35+
36+
command, _, err := root.Find([]string{"self", "doc"})
37+
if err != nil {
38+
t.Fatalf("unexpected error: %v", err)
39+
}
40+
41+
if !allowsMissingConfig(command) {
42+
t.Fatal("expected lets self doc to allow missing config")
43+
}
44+
})
45+
46+
t.Run("top level doc does not match self", func(t *testing.T) {
47+
root := cmdpkg.CreateRootCommand("v0.0.0-test", "")
48+
root.AddCommand(&cobra.Command{Use: "doc"})
49+
50+
command, _, err := root.Find([]string{"doc"})
51+
if err != nil {
52+
t.Fatalf("unexpected error: %v", err)
53+
}
54+
55+
if allowsMissingConfig(command) {
56+
t.Fatal("expected top-level doc to require config")
57+
}
58+
})
59+
}

internal/cmd/doc.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ func initDocCommand(openURL func(string) error) *cobra.Command {
1414
Aliases: []string{"docs"},
1515
Short: "Open lets documentation in browser",
1616
Args: cobra.NoArgs,
17-
if err := openURL(letsDocsURL); err != nil {
17+
RunE: func(cmd *cobra.Command, args []string) error {
18+
if err := openURL(letsDocsURL); err != nil {
1819
return fmt.Errorf("can not open documentation: %w", err)
1920
}
2021

2122
fmt.Fprintf(cmd.OutOrStdout(), "Opening %s\n", letsDocsURL)
2223

2324
return nil
24-
return nil
2525
},
2626
}
2727

internal/cmd/root_test.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,22 +181,18 @@ func TestSelfCmd(t *testing.T) {
181181
called := false
182182
gotURL := ""
183183

184-
prevOpenURL := openURL
185-
openURL = func(url string) error {
184+
openURL := func(url string) error {
186185
called = true
187186
gotURL = url
188187

189188
return nil
190189
}
191-
defer func() {
192-
openURL = prevOpenURL
193-
}()
194190

195191
rootCmd := CreateRootCommand("v0.0.0-test", "")
196192
rootCmd.SetArgs([]string{"self", "doc"})
197193
rootCmd.SetOut(bufOut)
198194
rootCmd.SetErr(bufOut)
199-
InitSelfCmd(rootCmd, "v0.0.0-test")
195+
initSelfCmd(rootCmd, "v0.0.0-test", openURL)
200196

201197
err := rootCmd.Execute()
202198
if err != nil {
@@ -215,19 +211,15 @@ func TestSelfCmd(t *testing.T) {
215211
t.Run("should return opener error for documentation command", func(t *testing.T) {
216212
bufOut := new(bytes.Buffer)
217213

218-
prevOpenURL := openURL
219-
openURL = func(url string) error {
214+
openURL := func(url string) error {
220215
return errors.New("open failed")
221216
}
222-
defer func() {
223-
openURL = prevOpenURL
224-
}()
225217

226218
rootCmd := CreateRootCommand("v0.0.0-test", "")
227219
rootCmd.SetArgs([]string{"self", "doc"})
228220
rootCmd.SetOut(bufOut)
229221
rootCmd.SetErr(bufOut)
230-
InitSelfCmd(rootCmd, "v0.0.0-test")
222+
initSelfCmd(rootCmd, "v0.0.0-test", openURL)
231223

232224
err := rootCmd.Execute()
233225
if err == nil {

internal/cmd/self.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import (
55
"github.com/spf13/cobra"
66
)
77

8-
var openURL = util.OpenURL
9-
108
// InitSelfCmd intializes root 'self' subcommand.
119
func InitSelfCmd(rootCmd *cobra.Command, version string) {
10+
initSelfCmd(rootCmd, version, util.OpenURL)
11+
}
12+
13+
func initSelfCmd(rootCmd *cobra.Command, version string, openURL func(string) error) {
1214
selfCmd := &cobra.Command{
1315
Use: "self",
1416
Hidden: false,

internal/util/browser.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,25 @@ import (
66
"runtime"
77
)
88

9-
func browserCommand(goos string, url string) (string, []string, error) {
9+
func browserCommand(goos string, url string) (*exec.Cmd, error) {
1010
switch goos {
1111
case "darwin":
12-
return "open", []string{url}, nil
12+
return exec.Command("open", url), nil
1313
case "linux":
14-
return "xdg-open", []string{url}, nil
14+
return exec.Command("xdg-open", url), nil
1515
default:
16-
return "", nil, fmt.Errorf("unsupported platform %q", goos)
16+
return nil, fmt.Errorf("unsupported platform %q", goos)
1717
}
1818
}
1919

2020
func OpenURL(url string) error {
21-
name, args, err := browserCommand(runtime.GOOS, url)
21+
cmd, err := browserCommand(runtime.GOOS, url)
2222
if err != nil {
2323
return err
2424
}
2525

26-
cmd := exec.Command(name, args...)
2726
if err := cmd.Start(); err != nil {
28-
return fmt.Errorf("start %s: %w", name, err)
27+
return fmt.Errorf("start %s: %w", cmd.Path, err)
2928
}
3029

3130
if cmd.Process != nil {

internal/util/browser_test.go

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,50 @@ package util
22

33
import (
44
"reflect"
5+
"strings"
56
"testing"
67
)
78

89
func TestBrowserCommand(t *testing.T) {
910
t.Run("darwin", func(t *testing.T) {
10-
name, args, err := browserCommand("darwin", "https://lets-cli.org")
11+
cmd, err := browserCommand("darwin", "https://lets-cli.org")
1112
if err != nil {
1213
t.Fatalf("unexpected error: %v", err)
1314
}
1415

15-
if name != "open" {
16-
t.Fatalf("expected open, got %q", name)
16+
if cmd.Args[0] != "open" {
17+
t.Fatalf("expected open, got %q", cmd.Args[0])
1718
}
1819

19-
expectedArgs := []string{"https://lets-cli.org"}
20-
if !reflect.DeepEqual(args, expectedArgs) {
21-
t.Fatalf("expected args %v, got %v", expectedArgs, args)
20+
expectedArgs := []string{"open", "https://lets-cli.org"}
21+
if !reflect.DeepEqual(cmd.Args, expectedArgs) {
22+
t.Fatalf("expected args %v, got %v", expectedArgs, cmd.Args)
2223
}
2324
})
2425

2526
t.Run("linux", func(t *testing.T) {
26-
name, args, err := browserCommand("linux", "https://lets-cli.org")
27+
cmd, err := browserCommand("linux", "https://lets-cli.org")
2728
if err != nil {
2829
t.Fatalf("unexpected error: %v", err)
2930
}
3031

31-
if name != "xdg-open" {
32-
t.Fatalf("expected xdg-open, got %q", name)
32+
if cmd.Args[0] != "xdg-open" {
33+
t.Fatalf("expected xdg-open, got %q", cmd.Args[0])
3334
}
3435

35-
expectedArgs := []string{"https://lets-cli.org"}
36-
if !reflect.DeepEqual(args, expectedArgs) {
37-
t.Fatalf("expected args %v, got %v", expectedArgs, args)
36+
expectedArgs := []string{"xdg-open", "https://lets-cli.org"}
37+
if !reflect.DeepEqual(cmd.Args, expectedArgs) {
38+
t.Fatalf("expected args %v, got %v", expectedArgs, cmd.Args)
3839
}
3940
})
4041

4142
t.Run("unsupported", func(t *testing.T) {
42-
_, _, err := browserCommand("windows", "https://lets-cli.org")
43+
_, err := browserCommand("windows", "https://lets-cli.org")
4344
if err == nil {
4445
t.Fatal("expected unsupported platform error")
4546
}
47+
if !strings.Contains(err.Error(), "windows") {
48+
t.Fatalf("expected error to mention platform %q, got %q", "windows", err.Error())
49+
}
4650
})
4751
}

tests/no_lets_file.bats

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@ setup() {
88
}
99

1010
NOT_EXISTED_LETS_FILE="lets-not-existed.yaml"
11+
TEMP_FAKE_BIN_DIR=""
12+
TEMP_OPENED_URL_FILE=""
13+
14+
teardown() {
15+
if [[ -n "${TEMP_FAKE_BIN_DIR}" ]]; then
16+
rm -rf "${TEMP_FAKE_BIN_DIR}"
17+
fi
18+
19+
if [[ -n "${TEMP_OPENED_URL_FILE}" ]]; then
20+
rm -f "${TEMP_OPENED_URL_FILE}"
21+
fi
22+
23+
TEMP_FAKE_BIN_DIR=""
24+
TEMP_OPENED_URL_FILE=""
25+
cleanup
26+
}
1127

1228
@test "no_lets_file: should not create .lets dir" {
1329
LETS_CONFIG=${NOT_EXISTED_LETS_FILE} run lets
@@ -52,40 +68,37 @@ NOT_EXISTED_LETS_FILE="lets-not-existed.yaml"
5268
}
5369

5470
@test "no_lets_file: lets self doc opens docs without config" {
55-
fake_bin_dir="$(mktemp -d)"
56-
opened_url_file="$(mktemp)"
57-
rm -f "${opened_url_file}"
71+
TEMP_FAKE_BIN_DIR="$(mktemp -d)"
72+
TEMP_OPENED_URL_FILE="$(mktemp)"
73+
rm -f "${TEMP_OPENED_URL_FILE}"
5874

59-
cat > "${fake_bin_dir}/xdg-open" <<'EOF'
75+
cat > "${TEMP_FAKE_BIN_DIR}/xdg-open" <<'EOF'
6076
#!/usr/bin/env bash
6177
printf "%s" "$1" > "${LETS_TEST_OPENED_URL_FILE}"
6278
EOF
63-
chmod +x "${fake_bin_dir}/xdg-open"
79+
chmod +x "${TEMP_FAKE_BIN_DIR}/xdg-open"
6480

65-
cat > "${fake_bin_dir}/open" <<'EOF'
81+
cat > "${TEMP_FAKE_BIN_DIR}/open" <<'EOF'
6682
#!/usr/bin/env bash
6783
printf "%s" "$1" > "${LETS_TEST_OPENED_URL_FILE}"
6884
EOF
69-
chmod +x "${fake_bin_dir}/open"
85+
chmod +x "${TEMP_FAKE_BIN_DIR}/open"
7086

71-
PATH="${fake_bin_dir}:${PATH}" \
87+
PATH="${TEMP_FAKE_BIN_DIR}:${PATH}" \
7288
LETS_CONFIG=${NOT_EXISTED_LETS_FILE} \
73-
LETS_TEST_OPENED_URL_FILE="${opened_url_file}" \
89+
LETS_TEST_OPENED_URL_FILE="${TEMP_OPENED_URL_FILE}" \
7490
run lets self doc
7591

7692
assert_success
7793

7894
for _ in $(seq 1 20); do
79-
if [[ -f "${opened_url_file}" ]]; then
95+
if [[ -f "${TEMP_OPENED_URL_FILE}" ]]; then
8096
break
8197
fi
8298
sleep 0.1
8399
done
84100

85-
run cat "${opened_url_file}"
101+
run cat "${TEMP_OPENED_URL_FILE}"
86102
assert_success
87-
assert_output "https://lets-cli.org/docs/quick_start"
88-
89-
rm -rf "${fake_bin_dir}"
90-
rm -f "${opened_url_file}"
103+
assert_output "https://lets-cli.org/docs/config"
91104
}

0 commit comments

Comments
 (0)