Skip to content

Commit

Permalink
Merge pull request #198 from leandroncbrito/create-command
Browse files Browse the repository at this point in the history
kool create command
  • Loading branch information
fabriciojs authored Nov 25, 2020
2 parents 805f616 + 74ef333 commit fd71b81
Show file tree
Hide file tree
Showing 21 changed files with 419 additions and 33 deletions.
18 changes: 16 additions & 2 deletions cmd/builder/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,16 @@ type Runner interface {
LookPath() error
}

// Command interface comprehends bot Runner and Builder interfaces
// Parser holds available methods for parse commands
type Parser interface {
Parse(string) error
}

// Command interface comprehends bot Runner, Builder, Parser interfaces
type Command interface {
Builder
Runner
Parser
}

// NewCommand Create a new command.
Expand All @@ -51,7 +57,6 @@ func ParseCommand(line string) (command *DefaultCommand, err error) {
}

command = &DefaultCommand{parsed[0], parsed[1:]}

return
}

Expand Down Expand Up @@ -94,3 +99,12 @@ func (c *DefaultCommand) Exec(args ...string) (outStr string, err error) {
outStr, err = shell.Exec(c.command, finalArgs...)
return
}

// Parse calls the ParseCommand function
func (c *DefaultCommand) Parse(line string) (err error) {
if parsed, err := ParseCommand(line); err == nil {
*c = *parsed
}

return
}
16 changes: 16 additions & 0 deletions cmd/builder/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,19 @@ func TestInteractiveArgs(t *testing.T) {
t.Errorf("Interactive failed; expected output 'x', got '%s'", output)
}
}

func TestParse(t *testing.T) {
line := "echo 'xxx'"

cmd := NewCommand("")
err := cmd.Parse(line)

if err != nil {
t.Errorf("failed to parse proper command line onto Command; error: %s", err)
return
}

if len(cmd.args) != 1 || cmd.command != "echo" || cmd.args[0] != "xxx" {
t.Errorf("ParseCommand failed; given %s got %v", line, cmd.String())
}
}
24 changes: 16 additions & 8 deletions cmd/builder/fake_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package builder

// FakeCommand implements the Command interface and is used for mocking on testing scenarios
type FakeCommand struct {
ArgsAppend []string
ArgsInteractive []string
ArgsExec []string
CalledAppendArgs bool
CalledString bool
CalledLookPath bool
CalledInteractive bool
CalledExec bool
ArgsAppend []string
ArgsInteractive []string
ArgsExec []string
CalledAppendArgs bool
CalledString bool
CalledLookPath bool
CalledInteractive bool
CalledExec bool
CalledParseCommand bool

MockExecOut string
MockError error
Expand Down Expand Up @@ -51,3 +52,10 @@ func (f *FakeCommand) Exec(args ...string) (outStr string, err error) {
err = f.MockError
return
}

// Parse call the ParseCommand function
func (f *FakeCommand) Parse(line string) (err error) {
f.CalledParseCommand = true
err = f.MockError
return
}
86 changes: 86 additions & 0 deletions cmd/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package cmd

import (
"fmt"
"kool-dev/kool/cmd/builder"
"kool-dev/kool/cmd/presets"
"os"

"github.com/spf13/cobra"
)

// KoolCreate holds handlers and functions to implement the preset command logic
type KoolCreate struct {
DefaultKoolService
parser presets.Parser
createCommand builder.Command
KoolPreset
}

func init() {
var (
create = NewKoolCreate()
createCmd = NewCreateCommand(create)
)

rootCmd.AddCommand(createCmd)
}

// NewKoolCreate creates a new handler for create logic
func NewKoolCreate() *KoolCreate {
return &KoolCreate{
*newDefaultKoolService(),
&presets.DefaultParser{},
&builder.DefaultCommand{},
*NewKoolPreset(),
}
}

// Execute runs the create logic with incoming arguments.
func (c *KoolCreate) Execute(originalArgs []string) (err error) {
preset := originalArgs[0]
dir := originalArgs[1]

c.parser.LoadPresets(presets.GetAll())

if !c.parser.Exists(preset) {
err = fmt.Errorf("Unknown preset %s", preset)
return
}

createCmd, err := c.parser.GetCreateCommand(preset)

if err != nil {
return
}

err = c.createCommand.Parse(createCmd)

if err != nil {
return
}

err = c.createCommand.Interactive(dir)

if err != nil {
return
}

_ = os.Chdir(dir)

err = c.KoolPreset.Execute([]string{preset})

return
}

// NewCreateCommand initializes new kool create command
func NewCreateCommand(create *KoolCreate) (createCmd *cobra.Command) {
createCmd = &cobra.Command{
Use: "create [preset] [project]",
Short: "Create a new project using preset",
Args: cobra.ExactArgs(2),
Run: DefaultCommandRunFunction(create),
}

return
}
126 changes: 126 additions & 0 deletions cmd/create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package cmd

import (
"bytes"
"kool-dev/kool/cmd/builder"
"kool-dev/kool/cmd/presets"
"kool-dev/kool/cmd/shell"
"testing"
)

func newFakeKoolCreate() *KoolCreate {
return &KoolCreate{
*newFakeKoolService(),
&presets.FakeParser{},
&builder.FakeCommand{},
*newFakeKoolPreset(),
}
}

func TestNewKoolCreate(t *testing.T) {
k := NewKoolCreate()

if _, ok := k.DefaultKoolService.out.(*shell.DefaultOutputWriter); !ok {
t.Errorf("unexpected shell.OutputWriter on default KoolCreate instance")
}

if _, ok := k.DefaultKoolService.exiter.(*shell.DefaultExiter); !ok {
t.Errorf("unexpected shell.Exiter on default KoolCreate instance")
}

if _, ok := k.DefaultKoolService.in.(*shell.DefaultInputReader); !ok {
t.Errorf("unexpected shell.InputReader on default KoolCreate instance")
}

if _, ok := k.createCommand.(*builder.DefaultCommand); !ok {
t.Errorf("unexpected builder.Command on default KoolCreate instance")
}

if _, ok := k.parser.(*presets.DefaultParser); !ok {
t.Errorf("unexpected presets.Parser on default KoolCreate instance")
}
}

func TestNewKoolCreateCommand(t *testing.T) {
f := newFakeKoolCreate()

f.parser.(*presets.FakeParser).MockExists = true
f.KoolPreset.parser.(*presets.FakeParser).MockExists = true
f.parser.(*presets.FakeParser).MockCreateCommand = "kool docker create command"

cmd := NewCreateCommand(f)
cmd.SetArgs([]string{"laravel", "my-app"})

if err := cmd.Execute(); err != nil {
t.Errorf("unexpected error executing create command; error: %v", err)
}

if !f.parser.(*presets.FakeParser).CalledLoadPresets {
t.Error("did not call parser.LoadPresets")
}

if !f.parser.(*presets.FakeParser).CalledExists {
t.Error("did not call parser.Exists")
}

if !f.parser.(*presets.FakeParser).CalledGetCreateCommand {
t.Error("did not call parser.GetCreateCommand")
}

if !f.createCommand.(*builder.FakeCommand).CalledParseCommand {
t.Error("did not call Parse on KoolCreate.createCommand Command")
}

if !f.createCommand.(*builder.FakeCommand).CalledInteractive {
t.Error("did not call Interactive on KoolCreate.createCommand Command")
}

if !f.out.(*shell.FakeOutputWriter).CalledSetWriter {
t.Error("did not call SetWriter")
}
}

func TestInvalidPresetCreateCommand(t *testing.T) {
f := newFakeKoolCreate()
cmd := NewCreateCommand(f)

cmd.SetArgs([]string{"invalid", "my-app"})

if err := cmd.Execute(); err != nil {
t.Errorf("unexpected error executing preset command; error: %v", err)
}

if !f.parser.(*presets.FakeParser).CalledLoadPresets {
t.Error("did not call parser.LoadPresets")
}

if !f.parser.(*presets.FakeParser).CalledExists {
t.Error("did not call parser.Exists")
}

if !f.out.(*shell.FakeOutputWriter).CalledError {
t.Error("did not call Error")
}

expected := "Unknown preset invalid"
output := f.out.(*shell.FakeOutputWriter).Err.Error()

if expected != output {
t.Errorf("expecting error '%s', got '%s'", expected, output)
}

if !f.exiter.(*shell.FakeExiter).Exited() {
t.Error("did not call Exit")
}
}

func TestNoArgsNewCreateCommand(t *testing.T) {
f := newFakeKoolCreate()

cmd := NewCreateCommand(f)
cmd.SetOut(bytes.NewBufferString(""))

if err := cmd.Execute(); err == nil {
t.Error("expecting no arguments error executing create command")
}
}
4 changes: 3 additions & 1 deletion cmd/preset.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func NewKoolPreset() *KoolPreset {
return &KoolPreset{
*newDefaultKoolService(),
&KoolPresetFlags{false},
&presets.DefaultParser{Presets: presets.GetAll()},
&presets.DefaultParser{},
shell.NewTerminalChecker(),
shell.NewPromptSelect(),
}
Expand All @@ -67,6 +67,8 @@ func (p *KoolPreset) Execute(args []string) (err error) {
preset = args[0]
}

p.parser.LoadPresets(presets.GetAll())

if !p.parser.Exists(preset) {
err = fmt.Errorf("Unknown preset %s", preset)
return
Expand Down
29 changes: 22 additions & 7 deletions cmd/presets/fake_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ package presets

// FakeParser implements all fake behaviors for using parser in tests.
type FakeParser struct {
CalledExists, CalledLookUpFiles, CalledWriteFiles, CalledGetPresets, CalledGetLanguages bool
CalledExists, CalledLookUpFiles, CalledWriteFiles, CalledGetCreateCommand, CalledGetPresets, CalledGetLanguages, CalledLoadPresets bool

MockExists bool
MockFoundFiles []string
MockFileError string
MockError error
MockLanguages []string
MockPresets []string
MockExists bool
MockFoundFiles []string
MockFileError string
MockError error
MockCreateCommand string
MockLanguages []string
MockPresets []string
MockAllPresets map[string]map[string]string
}

// Exists check if preset exists
Expand All @@ -19,6 +21,13 @@ func (f *FakeParser) Exists(preset string) (exists bool) {
return
}

// GetCreateCommand gets the command to create a new project
func (f *FakeParser) GetCreateCommand(preset string) (cmd string, err error) {
f.CalledGetCreateCommand = true
cmd = f.MockCreateCommand
return
}

// GetLanguages get all presets languages
func (f *FakeParser) GetLanguages() (languages []string) {
f.CalledGetLanguages = true
Expand Down Expand Up @@ -47,3 +56,9 @@ func (f *FakeParser) WriteFiles(preset string) (fileError string, err error) {
err = f.MockError
return
}

//LoadPresets loads all presets
func (f *FakeParser) LoadPresets(presets map[string]map[string]string) {
f.CalledLoadPresets = true
f.MockAllPresets = presets
}
7 changes: 7 additions & 0 deletions cmd/presets/fake_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,11 @@ func TestFakeParser(t *testing.T) {
if !f.CalledGetLanguages || len(languages) != 1 || languages[0] != "php" {
t.Error("failed to use mocked GetPresets function on FakeParser")
}

f.MockCreateCommand = "create"
createCommand, _ := f.GetCreateCommand("")

if !f.CalledGetCreateCommand || createCommand == "" || createCommand != "create" {
t.Error("failed to use mocked GetCreateCommand function on FakeParser")
}
}
Loading

0 comments on commit fd71b81

Please sign in to comment.