From b0b9bf891393311dfeb2a7008895794c4904618c Mon Sep 17 00:00:00 2001 From: Rick <1450685+LinuxSuRen@users.noreply.github.com> Date: Sun, 4 Jun 2023 14:03:01 +0800 Subject: [PATCH] add unit tests for func cmd (#84) Co-authored-by: Rick --- cmd/function.go | 81 ++++++++++++++++++++++++++++++++++++++++++ cmd/function_test.go | 52 +++++++++++++++++++++++++++ cmd/root.go | 2 +- pkg/render/template.go | 17 +++++---- 4 files changed, 145 insertions(+), 7 deletions(-) create mode 100644 cmd/function.go create mode 100644 cmd/function_test.go diff --git a/cmd/function.go b/cmd/function.go new file mode 100644 index 00000000..46593c71 --- /dev/null +++ b/cmd/function.go @@ -0,0 +1,81 @@ +package cmd + +import ( + "fmt" + "go/ast" + "go/doc" + "go/parser" + "go/token" + "path/filepath" + "reflect" + "runtime" + "strings" + + "github.com/linuxsuren/api-testing/pkg/render" + "github.com/spf13/cobra" +) + +func createFunctionCmd() (c *cobra.Command) { + c = &cobra.Command{ + Use: "func", + Short: "Print all the supported functions", + RunE: func(cmd *cobra.Command, args []string) (err error) { + if len(args) > 0 { + name := args[0] + if fn, ok := render.FuncMap()[name]; ok { + cmd.Println(reflect.TypeOf(fn)) + desc := FuncDescription(fn) + if desc != "" { + fmt.Println(desc) + } + } else { + cmd.Println("No such function") + } + } else { + for name, fn := range render.FuncMap() { + cmd.Println(name, reflect.TypeOf(fn)) + } + } + return + }, + } + return +} + +// Get the name and path of a func +func FuncPathAndName(f interface{}) string { + return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() +} + +// Get the name of a func (with package path) +func FuncName(f interface{}) string { + splitFuncName := strings.Split(FuncPathAndName(f), ".") + return splitFuncName[len(splitFuncName)-1] +} + +// Get description of a func +func FuncDescription(f interface{}) (desc string) { + fileName, _ := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).FileLine(0) + funcName := FuncName(f) + fset := token.NewFileSet() + + // Parse src + parsedAst, err := parser.ParseFile(fset, fileName, nil, parser.ParseComments) + if err == nil { + pkg := &ast.Package{ + Name: "Any", + Files: make(map[string]*ast.File), + } + pkg.Files[fileName] = parsedAst + + importPath, _ := filepath.Abs("/") + myDoc := doc.New(pkg, importPath, doc.AllDecls) + for _, theFunc := range myDoc.Funcs { + if theFunc.Name == funcName { + desc = theFunc.Doc + break + } + } + } + return +} diff --git a/cmd/function_test.go b/cmd/function_test.go new file mode 100644 index 00000000..2ca1100d --- /dev/null +++ b/cmd/function_test.go @@ -0,0 +1,52 @@ +package cmd_test + +import ( + "bytes" + "testing" + + "github.com/linuxsuren/api-testing/cmd" + fakeruntime "github.com/linuxsuren/go-fake-runtime" + "github.com/stretchr/testify/assert" +) + +func TestCreateFunctionCommand(t *testing.T) { + tests := []struct { + name string + args []string + verify func(t *testing.T, output string) + }{{ + name: "normal", + args: []string{"func"}, + verify: func(t *testing.T, output string) { + assert.NotEmpty(t, output) + }, + }, { + name: "with function name", + args: []string{"func", "clean"}, + verify: func(t *testing.T, output string) { + assert.NotEmpty(t, output) + }, + }, { + name: "with not exit function", + args: []string{"func", "fake"}, + verify: func(t *testing.T, output string) { + assert.Equal(t, "No such function\n", output) + }, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := cmd.NewRootCmd(fakeruntime.FakeExecer{ExpectOS: "linux"}, cmd.NewFakeGRPCServer()) + + buf := new(bytes.Buffer) + c.SetOut(buf) + c.SetArgs(tt.args) + + err := c.Execute() + assert.NoError(t, err) + + if tt.verify != nil { + tt.verify(t, buf.String()) + } + }) + } +} diff --git a/cmd/root.go b/cmd/root.go index 707ed1d9..cadce91e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -19,7 +19,7 @@ func NewRootCmd(execer fakeruntime.Execer, gRPCServer gRPCServer) (c *cobra.Comm c.AddCommand(createInitCommand(execer), createRunCommand(), createSampleCmd(), createServerCmd(gRPCServer), createJSONSchemaCmd(), - createServiceCommand(execer)) + createServiceCommand(execer), createFunctionCmd()) return } diff --git a/pkg/render/template.go b/pkg/render/template.go index effca169..ffbfadd8 100644 --- a/pkg/render/template.go +++ b/pkg/render/template.go @@ -13,12 +13,8 @@ import ( func Render(name, text string, ctx interface{}) (result string, err error) { var tpl *template.Template if tpl, err = template.New(name). - Funcs(sprig.FuncMap()). - Funcs(template.FuncMap{ - "randomKubernetesName": func() string { - return util.String(8) - }, - }).Parse(text); err == nil { + Funcs(FuncMap()). + Parse(text); err == nil { buf := new(bytes.Buffer) if err = tpl.Execute(buf, ctx); err == nil { result = strings.TrimSpace(buf.String()) @@ -26,3 +22,12 @@ func Render(name, text string, ctx interface{}) (result string, err error) { } return } + +// FuncMap reutrns all the supported functions +func FuncMap() template.FuncMap { + funcs := sprig.FuncMap() + funcs["randomKubernetesName"] = func() string { + return util.String(8) + } + return funcs +}