Skip to content

Commit

Permalink
added sandbox test
Browse files Browse the repository at this point in the history
  • Loading branch information
rsteube committed Jan 1, 2023
1 parent 21046e6 commit 41eec72
Show file tree
Hide file tree
Showing 12 changed files with 364 additions and 5 deletions.
2 changes: 1 addition & 1 deletion complete.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func complete(cmd *cobra.Command, args []string) (string, error) {
return ActionMessage(err.Error()).Invoke(Context{CallbackValue: current}).value(shell, current), nil
}

context := newContext(append(targetArgs, current))
context := NewContext(append(targetArgs, current))

// TODO needs more cleanup and tests
var targetAction Action
Expand Down
24 changes: 23 additions & 1 deletion context.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package carapace

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"

"github.com/rsteube/carapace/internal/common"
"github.com/rsteube/carapace/internal/shell/zsh"
"github.com/rsteube/carapace/third_party/github.com/drone/envsubst"
"github.com/rsteube/carapace/third_party/golang.org/x/sys/execabs"
Expand All @@ -23,9 +25,11 @@ type Context struct {
Env []string
// Dir contains the working directory for current context
Dir string

mockedReplies map[string]string
}

func newContext(args []string) Context {
func NewContext(args []string) Context {
context := Context{
CallbackValue: args[len(args)-1],
Args: args[:len(args)-1],
Expand All @@ -35,6 +39,16 @@ func newContext(args []string) Context {
if wd, err := os.Getwd(); err == nil {
context.Dir = wd
}

// TODO needed for sandbox tests. is this a security hazard?
if value, exists := os.LookupEnv("CARAPACE_SANDBOX"); exists {
var m common.Mock
if err := json.Unmarshal([]byte(value), &m); err != nil {
panic(err.Error()) // TODO
}
context.Dir = m.Dir
context.mockedReplies = m.Replies
}
return context
}

Expand Down Expand Up @@ -71,6 +85,14 @@ func (c Context) Envsubst(s string) (string, error) {
// Env and Dir are set using the Context.
// See exec.Command for most details.
func (c Context) Command(name string, arg ...string) *execabs.Cmd {
if c.mockedReplies != nil {
if m, err := json.Marshal(append([]string{name}, arg...)); err == nil {
if reply, exists := c.mockedReplies[string(m)]; exists {
return execabs.Command("echo", reply)
}
}
}

cmd := execabs.Command(name, arg...)
cmd.Env = c.Env
cmd.Dir = c.Dir
Expand Down
48 changes: 48 additions & 0 deletions example/cmd/action_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package cmd

import (
"testing"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace/pkg/sandbox"
"github.com/rsteube/carapace/pkg/style"
)

func TestAction(t *testing.T) {
sandbox.Run(t, "github.com/rsteube/carapace/example")(func(s *sandbox.Sandbox) {
s.Files(
"dirA/file1.txt", "",
"dirA/file2.png", "",
"dirB/dirC/file3.go", "",
"dirB/file4.md", "",
"file5.go", "",
)

s.Reply("git", "remote").With("origin\nfork")

s.Run("action", "--callback", "").Expect(carapace.ActionMessage("values flag is not set"))
s.Run("action", "--values", "first", "--callback", "").Expect(carapace.ActionMessage("values flag is set to: 'first'"))
s.Run("action", "--directories", "").Expect(carapace.ActionValues("dirA/", "dirB/").StyleF(style.ForPath))
s.Run("action", "--directories", "dirB/").Expect(carapace.ActionValues("dirC/").Prefix("dirB/").StyleF(style.ForPath))
s.Run("action", "--exec-command", "").Expect(carapace.ActionValues("origin", "fork"))
s.Run("action", "--files", "").Expect(carapace.ActionValues("dirA/", "dirB/", "file5.go").StyleF(style.ForPath))
s.Run("action", "--files-filtered", "").Expect(carapace.ActionValues("dirA/", "dirB/").StyleF(style.ForPath))
s.Run("action", "--files-filtered", "dirB/").Expect(carapace.ActionValues("dirC/", "file4.md").Prefix("dirB/").StyleF(style.ForPath))
s.Run("action", "--import", "").Expect(carapace.ActionValues("first", "second", "third"))
s.Run("action", "--import", "s").Expect(carapace.ActionValues("second"))
s.Run("action", "--message", "").Expect(carapace.ActionMessage("example message"))
s.Run("action", "--message-multiple", "t").Expect(carapace.Batch(carapace.ActionMessage("first message"), carapace.ActionMessage("second message"), carapace.ActionMessage("third message"), carapace.ActionValues("one", "two", "three")).ToA())
s.Run("action", "--multiparts", "").Expect(carapace.ActionValues("userA", "userB").Suffix(":"))
s.Run("action", "--multiparts", "userA:").Expect(carapace.ActionValues("groupA", "groupB").Prefix("userA:"))
s.Run("action", "--multiparts-nested", "").Expect(carapace.ActionValues("DIRECTORY", "FILE", "VALUE").Suffix("="))
s.Run("action", "--multiparts-nested", "VALUE=").Expect(carapace.ActionValues("one", "two", "three").Prefix("VALUE="))
s.Run("action", "--multiparts-nested", "VALUE=two,").Expect(carapace.ActionValues("DIRECTORY", "FILE").Prefix("VALUE=two,").Suffix("="))
s.Run("action", "--multiparts-nested", "VALUE=two,DIRECTORY=").Expect(carapace.ActionValues("dirA/", "dirB/").StyleF(style.ForPath).Prefix("VALUE=two,DIRECTORY="))
s.Run("action", "--styled-values", "s").Expect(carapace.ActionStyledValues("second", style.Blue))
s.Run("action", "--styled-values-described", "t").Expect(carapace.ActionStyledValuesDescribed("third", "description of third", style.Of("#112233", style.Italic), "thirdalias", "description of third", style.BgBrightMagenta))
s.Run("action", "--values", "sec").Expect(carapace.ActionValues("second"))
s.Run("action", "--values-described", "third").Expect(carapace.ActionValuesDescribed("third", "description of third"))
s.Run("action", "pos").Expect(carapace.ActionValues("positional1", "positional1 with space"))
s.Run("action", "p1", "positional2 ").Expect(carapace.ActionValues("positional2 with space"))
})
}
2 changes: 1 addition & 1 deletion example/cmd/multiparts.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var multipartsCmd = &cobra.Command{

func init() {
multipartsCmd.Flags().String("at", "", "multiparts with @ as divider")
multipartsCmd.Flags().String("colon", "", "multiparts with : as divider ")
multipartsCmd.Flags().String("colon", "", "multiparts with : as divider")
multipartsCmd.Flags().String("comma", "", "multiparts with , as divider")
multipartsCmd.Flags().String("dot", "", "multiparts with . as divider")
multipartsCmd.Flags().String("dotdotdot", "", "multiparts with ... as divider")
Expand Down
31 changes: 31 additions & 0 deletions example/cmd/multiparts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cmd

import (
"testing"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace/pkg/sandbox"
"github.com/rsteube/carapace/pkg/style"
)

func TestMultiparts(t *testing.T) {
sandbox.Run(t, "github.com/rsteube/carapace/example")(func(s *sandbox.Sandbox) {
s.Files(
"dirA/file1.txt", "",
"dirA/file2.png", "",
"dirB/dirC/file3.go", "",
"dirB/file4.md", "",
"file5.go", "",
)
s.Run("multiparts", "").Expect(carapace.ActionValues("DIRECTORY", "FILE", "VALUE").Suffix("="))
s.Run("multiparts", "D").Expect(carapace.ActionValues("DIRECTORY").Suffix("="))
s.Run("multiparts", "DIRECTORY").Expect(carapace.ActionValues("DIRECTORY").Suffix("="))
s.Run("multiparts", "DIRECTORY=").Expect(carapace.ActionValues("dirA/", "dirB/").StyleF(style.ForPath).Prefix("DIRECTORY="))
s.Run("multiparts", "VALUE=").Expect(carapace.ActionValues("one", "two", "three").Prefix("VALUE="))
s.Run("multiparts", "VALUE=o").Expect(carapace.ActionValues("one").Prefix("VALUE="))
s.Run("multiparts", "VALUE=one,").Expect(carapace.ActionValues("DIRECTORY", "FILE").Prefix("VALUE=one,").Suffix("="))
s.Run("multiparts", "VALUE=one,F").Expect(carapace.ActionValues("FILE").Prefix("VALUE=one,").Suffix("="))
s.Run("multiparts", "VALUE=one,FILE=").Expect(carapace.ActionValues("dirA/", "dirB/", "file5.go").StyleF(style.ForPath).Prefix("VALUE=one,FILE="))
s.Run("multiparts", "VALUE=one,FILE=dirB/").Expect(carapace.ActionValues("dirC/", "file4.md").Prefix("dirB/").StyleF(style.ForPath).Prefix("VALUE=one,FILE="))
})
}
66 changes: 66 additions & 0 deletions example/cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (

"github.com/rsteube/carapace"
"github.com/rsteube/carapace/internal/assert"
"github.com/rsteube/carapace/pkg/sandbox"
"github.com/rsteube/carapace/pkg/style"
)

func testScript(t *testing.T, shell string, file string) {
Expand Down Expand Up @@ -53,3 +55,67 @@ func TestXonsh(t *testing.T) {
func TestZsh(t *testing.T) {
testScript(t, "zsh", "./_test/zsh.sh")
}

func TestRoot(t *testing.T) {
sandbox.Run(t, "github.com/rsteube/carapace/example")(func(s *sandbox.Sandbox) {
s.Run("").Expect(carapace.Batch(
carapace.ActionValuesDescribed(
"action", "action example",
"alias", "action example",
"flag", "flag example",
).Style(style.Blue).Tag("main commands"),
carapace.ActionValuesDescribed(
"modifier", "modifier example",
).Style(style.Yellow).Tag("modifier commands"),
carapace.ActionValuesDescribed(
"injection", "just trying to break things",
).Style(style.Magenta).Tag("test commands"),
carapace.ActionValuesDescribed(
"completion", "Generate the autocompletion script for the specified shell",
"help", "Help about any command",
"multiparts", "multiparts example",
"special", "",
).Tag("other commands"),
).ToA())

s.Run("a").Expect(carapace.ActionStyledValuesDescribed(
"action", "action example", style.Blue,
"alias", "action example", style.Blue,
).Tag("main commands"))

s.Run("action").Expect(carapace.ActionStyledValuesDescribed(
"action", "action example", style.Blue,
).Tag("main commands"))

s.Run("-").Expect(carapace.ActionValuesDescribed(
"--array", "multiflag",
"-a", "multiflag",
"--persistentFlag", "Help message for persistentFlag",
"-p", "Help message for persistentFlag",
"--toggle", "Help message for toggle",
"-t", "Help message for toggle",
).Tag("flags"))

s.Run("--").Expect(carapace.ActionValuesDescribed(
"--array", "multiflag",
"--persistentFlag", "Help message for persistentFlag",
"--toggle", "Help message for toggle",
).Tag("flags"))

s.Run("--a").Expect(carapace.ActionValuesDescribed(
"--array", "multiflag",
).Tag("flags"))

s.Run("--array").Expect(carapace.ActionValuesDescribed(
"--array", "multiflag",
).Tag("flags"))

s.Run("--array", "", "--a").Expect(carapace.ActionValuesDescribed(
"--array", "multiflag",
).Tag("flags"))

s.Run("-a", "", "--a").Expect(carapace.ActionValuesDescribed(
"--array", "multiflag",
).Tag("flags"))
})
}
6 changes: 6 additions & 0 deletions internal/common/mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package common

type Mock struct {
Dir string
Replies map[string]string
}
4 changes: 4 additions & 0 deletions internal/common/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
"github.com/rsteube/carapace/pkg/style"
)

// FromInvokedAction provides access to RawValues within an InvokedAction.
// It is intended for testing purposes in Sandbox (circumventing dependency issues).
var FromInvokedAction func(action interface{}) RawValues

// RawValue represents a completion candidate.
type RawValue struct {
Value string
Expand Down
9 changes: 9 additions & 0 deletions invokedAction.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,12 @@ func (a InvokedAction) ToMultiPartsA(dividers ...string) Action {
func (a InvokedAction) value(shell string, callbackValue string) string {
return _shell.Value(shell, callbackValue, a.meta, a.rawValues)
}

func init() {
common.FromInvokedAction = func(i interface{}) common.RawValues {
if a, ok := i.(InvokedAction); ok {
return a.rawValues
}
return nil
}
}
Loading

0 comments on commit 41eec72

Please sign in to comment.