Skip to content

Commit

Permalink
adds tests for prompter template function
Browse files Browse the repository at this point in the history
lays ground for more local testing of templates.
  • Loading branch information
davidovich committed Dec 15, 2024
1 parent 96c496d commit 0b9d04e
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 6 deletions.
12 changes: 9 additions & 3 deletions pkg/summon/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"
"io"
"io/fs"
"io/ioutil"
"os"
"path"
"text/template"
Expand Down Expand Up @@ -36,6 +35,7 @@ type Driver struct {
flagsToRender []*flagValue
cmdToSpec map[*cobra.Command]*commandSpec
prompts map[string]string
prompter Prompter
}

// New creates the Driver.
Expand All @@ -45,6 +45,7 @@ func New(filesystem fs.FS, opts ...Option) (*Driver, error) {
execCommand: command.New,
cmdToSpec: map[*cobra.Command]*commandSpec{},
prompts: map[string]string{},
prompter: &Prompt{},
}

err := fs.WalkDir(d.fs, ".", func(path string, de fs.DirEntry, err error) error {
Expand Down Expand Up @@ -133,6 +134,11 @@ func (d *Driver) Configure(opts ...Option) error {
d.opts.data = map[string]interface{}{}
}

// override prompter
if d.opts.prompter != nil {
d.prompter = d.opts.prompter
}

d.opts.data["osArgs"] = os.Args

return nil
Expand All @@ -158,9 +164,9 @@ func (jv *jsonValue) Set(s string) error {
var j []byte
var err error
if s == "-" {
j, err = ioutil.ReadAll(jv.cmd.InOrStdin())
j, err = io.ReadAll(jv.cmd.InOrStdin())
} else {
j, err = ioutil.ReadFile(s)
j, err = os.ReadFile(s)
}
if err != nil {
return err
Expand Down
7 changes: 7 additions & 0 deletions pkg/summon/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,10 @@ type ConfigurableLister interface {
type Lister interface {
List(opts ...Option) ([]string, error)
}

// Prompter allows prompting the user.
type Prompter interface {
NewPrompt(userPrompt string)
Choose(choices []string) (string, error)
Input(defaultVal string) (string, error)
}
10 changes: 10 additions & 0 deletions pkg/summon/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ type options struct {
dryrun bool
// execCommand overrides the command used to run external processes
execCommand command.ExecCommandFn
//prompter
prompter Prompter
}

type helpInfo struct {
Expand Down Expand Up @@ -188,3 +190,11 @@ func (o *options) DefaultsFrom(conf config.Config) {
o.destination = conf.OutputDir
}
}

// WithPrompter configures the prompter. This is mostly used in testing.
func WithPrompter(p Prompter) Option {
return func(opts *options) error {
opts.prompter = p
return nil
}
}
34 changes: 31 additions & 3 deletions pkg/summon/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func summonFuncMap(d *Driver) template.FuncMap {
configRead: d.configRead,
cmdToSpec: d.cmdToSpec,
prompts: d.prompts,
prompter: d.prompter,
}
driverCopy.opts.argsConsumed = map[int]struct{}{}
driverCopy.opts.cobraCmd = nil
Expand Down Expand Up @@ -157,11 +158,12 @@ func summonFuncMap(d *Driver) template.FuncMap {
return "", fmt.Errorf("last parameter should be a default value or a list of choices")
}

pr := prompt.New().Ask(ask)
d.prompter.NewPrompt(ask)

if len(selectors) != 0 {
result, err = pr.Choose(selectors)
result, err = d.prompter.Choose(selectors)
} else {
result, err = pr.Input(defaultValue)
result, err = d.prompter.Input(defaultValue)
}

if err != nil {
Expand All @@ -181,3 +183,29 @@ func summonFuncMap(d *Driver) template.FuncMap {
},
}
}

type Prompt struct {
pr *prompt.Prompt
promptStr string
selectors []string
defaultVal string
}

func (p *Prompt) NewPrompt(userPrompt string) {
p.pr = prompt.New().Ask(userPrompt)
}

func (p *Prompt) Choose(choices []string) (string, error) {
if p.pr == nil {
return "", fmt.Errorf("prompter is not initialized")
}

return p.pr.Choose(choices)
}

func (p *Prompt) Input(defaultVal string) (string, error) {
if p.pr == nil {
return "", fmt.Errorf("prompter is not initialized")
}
return p.pr.Input(defaultVal)
}
62 changes: 62 additions & 0 deletions pkg/summon/template_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package summon

import (
"bytes"
"testing"
"testing/fstest"

"github.com/stretchr/testify/assert"
)

type testPrompter struct {
b *bytes.Buffer
choice int
userInput string
}

func (tpr *testPrompter) NewPrompt(userPrompt string) {
tpr.b = bytes.NewBufferString(userPrompt)
}

func (tpr *testPrompter) Choose(choices []string) (string, error) {
return choices[tpr.choice], nil
}

func (tpr *testPrompter) Input(defaultVal string) (string, error) {
if tpr.userInput == "" {
return defaultVal, nil
}
return tpr.userInput, nil
}

func TestPrompt(t *testing.T) {
testFs := fstest.MapFS{}
testFs["text.txt"] = &fstest.MapFile{Data: []byte("this is a text")}

tpr := &testPrompter{
choice: 1,
}
// create a summoner to summon text.txt at
s, err := New(testFs, WithPrompter(tpr))
assert.NoError(t, err)

ret, err := s.renderTemplate(`{{ prompt "slotA" "What is your name" "David" }}`)
assert.NoError(t, err)

// check default value
assert.Equal(t, "What is your name", tpr.b.String())
assert.Equal(t, "David", ret)

promptVal, err := s.renderTemplate(`{{ promptValue "slotA" }}`)
assert.NoError(t, err)
assert.Equal(t, "David", promptVal)

// test selection (choice is B by the testPrompter config)
ret, err = s.renderTemplate(`{{ prompt "continue" "Select One" (list "A" "B" "C") }}`)
assert.NoError(t, err)

assert.Equal(t, "B", ret)
promptVal, err = s.renderTemplate(`{{ promptValue "continue" }}`)
assert.NoError(t, err)
assert.Equal(t, "B", promptVal)
}

0 comments on commit 0b9d04e

Please sign in to comment.