You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
433 lines
11 KiB
433 lines
11 KiB
package main |
|
|
|
import ( |
|
"bytes" |
|
"fmt" |
|
"io/ioutil" |
|
"os" |
|
"path/filepath" |
|
"strings" |
|
|
|
"github.com/otokaze/mock/mockgen" |
|
"github.com/otokaze/mock/mockgen/model" |
|
) |
|
|
|
func genTest(parses []*parse) (err error) { |
|
for _, p := range parses { |
|
switch { |
|
case strings.HasSuffix(p.Path, "_mock.go") || |
|
strings.HasSuffix(p.Path, ".intf.go"): |
|
continue |
|
case strings.HasSuffix(p.Path, "dao.go") || |
|
strings.HasSuffix(p.Path, "service.go"): |
|
err = p.genTestMain() |
|
default: |
|
err = p.genUTTest() |
|
} |
|
if err != nil { |
|
break |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (p *parse) genUTTest() (err error) { |
|
var ( |
|
buffer bytes.Buffer |
|
impts = strings.Join([]string{ |
|
`"context"`, |
|
`"testing"`, |
|
`"github.com/smartystreets/goconvey/convey"`, |
|
}, "\n\t") |
|
content []byte |
|
) |
|
filename := strings.Replace(p.Path, ".go", "_test.go", -1) |
|
if _, err = os.Stat(filename); (_func == "" && err == nil) || |
|
(err != nil && os.IsExist(err)) { |
|
err = nil |
|
return |
|
} |
|
for _, impt := range p.Imports { |
|
impts += "\n\t" + impt |
|
} |
|
if _func == "" { |
|
buffer.WriteString(fmt.Sprintf(tpPackage, p.Package)) |
|
buffer.WriteString(fmt.Sprintf(tpImport, impts)) |
|
} |
|
for _, parseFunc := range p.Funcs { |
|
if _func != "" && _func != parseFunc.Name { |
|
continue |
|
} |
|
var ( |
|
methodK string |
|
tpVars string |
|
vars []string |
|
val []string |
|
notice = "Then " |
|
reset string |
|
) |
|
if parseFunc.Method != nil { |
|
switch { |
|
case strings.Contains(p.Path, "/library"): |
|
methodK = "" |
|
case strings.Contains(p.Path, "/service"): |
|
methodK = "s." |
|
case strings.Contains(p.Path, "/dao"): |
|
methodK = "d." |
|
} |
|
// if IsService(p.Package) { |
|
// methodK = "s." |
|
// } else { |
|
// methodK = "d." |
|
// } |
|
} |
|
tpTestFuncs := fmt.Sprintf(tpTestFunc, strings.Title(p.Package), parseFunc.Name, parseFunc.Name, "%s", "%s", "%s") |
|
tpTestFuncBeCall := methodK + parseFunc.Name + "(%s)\n\t\t\tconvCtx.Convey(\"%s\", func(convCtx convey.C) {" |
|
if parseFunc.Result == nil { |
|
tpTestFuncBeCall = fmt.Sprintf(tpTestFuncBeCall, "%s", "No return values") |
|
tpTestFuncs = fmt.Sprintf(tpTestFuncs, "%s", tpTestFuncBeCall, "%s") |
|
} |
|
for k, res := range parseFunc.Result { |
|
if res.K == "" { |
|
res.K = fmt.Sprintf("p%d", k+1) |
|
} |
|
var so string |
|
if res.V == "error" { |
|
res.K = "err" |
|
so = fmt.Sprintf("\tconvCtx.So(%s, convey.ShouldBeNil)", res.K) |
|
notice += "err should be nil." |
|
} else { |
|
so = fmt.Sprintf("\tconvCtx.So(%s, convey.ShouldNotBeNil)", res.K) |
|
val = append(val, res.K) |
|
} |
|
if len(parseFunc.Result) <= k+1 { |
|
if len(val) != 0 { |
|
notice += strings.Join(val, ",") + " should not be nil." |
|
} |
|
tpTestFuncBeCall = fmt.Sprintf(tpTestFuncBeCall, "%s", notice) |
|
res.K += " := " + tpTestFuncBeCall |
|
} else { |
|
res.K += ", %s" |
|
} |
|
tpTestFuncs = fmt.Sprintf(tpTestFuncs, "%s", res.K+"\n\t\t\t%s", "%s") |
|
tpTestFuncs = fmt.Sprintf(tpTestFuncs, "%s", "%s", so, "%s") |
|
} |
|
if parseFunc.Params == nil { |
|
tpTestFuncs = fmt.Sprintf(tpTestFuncs, "%s", "", "%s") |
|
} |
|
for k, pType := range parseFunc.Params { |
|
if pType.K == "" { |
|
pType.K = fmt.Sprintf("a%d", k+1) |
|
} |
|
var ( |
|
init string |
|
params = pType.K |
|
) |
|
switch { |
|
case strings.HasPrefix(pType.V, "context"): |
|
init = params + " = context.Background()" |
|
case strings.HasPrefix(pType.V, "[]byte"): |
|
init = params + " = " + pType.V + "(\"\")" |
|
case strings.HasPrefix(pType.V, "[]"): |
|
init = params + " = " + pType.V + "{}" |
|
case strings.HasPrefix(pType.V, "int") || |
|
strings.HasPrefix(pType.V, "uint") || |
|
strings.HasPrefix(pType.V, "float") || |
|
strings.HasPrefix(pType.V, "double"): |
|
init = params + " = " + pType.V + "(0)" |
|
case strings.HasPrefix(pType.V, "string"): |
|
init = params + " = \"\"" |
|
case strings.Contains(pType.V, "*xsql.Tx"): |
|
// init = params + ",_ = d.BeginTran(c)" |
|
init = params + ",_ = " + methodK + "BeginTran(c)" |
|
reset += "\n\t" + params + ".Commit()" |
|
case strings.HasPrefix(pType.V, "*"): |
|
init = params + " = " + strings.Replace(pType.V, "*", "&", -1) + "{}" |
|
case strings.Contains(pType.V, "chan"): |
|
init = params + " = " + pType.V |
|
case pType.V == "time.Time": |
|
init = params + " = time.Now()" |
|
case strings.Contains(pType.V, "chan"): |
|
init = params + " = " + pType.V |
|
default: |
|
init = params + " " + pType.V |
|
} |
|
vars = append(vars, "\t\t"+init) |
|
if len(parseFunc.Params) > k+1 { |
|
params += ", %s" |
|
} |
|
tpTestFuncs = fmt.Sprintf(tpTestFuncs, "%s", params, "%s") |
|
} |
|
if len(vars) > 0 { |
|
tpVars = fmt.Sprintf(tpVar, strings.Join(vars, "\n\t")) |
|
} |
|
tpTestFuncs = fmt.Sprintf(tpTestFuncs, tpVars, "%s") |
|
if reset != "" { |
|
tpTestResets := fmt.Sprintf(tpTestReset, reset) |
|
tpTestFuncs = fmt.Sprintf(tpTestFuncs, tpTestResets) |
|
} else { |
|
tpTestFuncs = fmt.Sprintf(tpTestFuncs, "") |
|
} |
|
buffer.WriteString(tpTestFuncs) |
|
} |
|
var ( |
|
file *os.File |
|
flag = os.O_RDWR | os.O_CREATE | os.O_APPEND |
|
) |
|
if file, err = os.OpenFile(filename, flag, 0644); err != nil { |
|
return |
|
} |
|
if _func == "" { |
|
content, _ = GoImport(filename, buffer.Bytes()) |
|
} else { |
|
content = buffer.Bytes() |
|
} |
|
if _, err = file.Write(content); err != nil { |
|
return |
|
} |
|
if err = file.Close(); err != nil { |
|
return |
|
} |
|
return |
|
} |
|
|
|
func (p *parse) genTestMain() (err error) { |
|
var ( |
|
buffer bytes.Buffer |
|
left, right int |
|
vars, mainFunc, fileAbs string |
|
) |
|
if fileAbs, err = filepath.Abs(p.Path); err != nil { |
|
return |
|
} |
|
var pathSplit []string |
|
if pathSplit = strings.Split(fileAbs, "/"); len(pathSplit) == 1 { |
|
pathSplit = strings.Split(fileAbs, "\\") |
|
} |
|
|
|
for index, value := range pathSplit { |
|
if value == "go-common" { |
|
left = index |
|
} |
|
if value == "main" || |
|
value == "ep" || |
|
value == "openplatform" || |
|
value == "live" || |
|
value == "video" || |
|
value == "tool" || |
|
value == "bbq" || |
|
value == "library" { |
|
right = index |
|
break |
|
} |
|
} |
|
var ( |
|
tomlPath string |
|
filePath = filepath.Dir(fileAbs) |
|
cmdFiles []os.FileInfo |
|
cmdPath = strings.Join(pathSplit[:right+2], "/") + "/cmd" |
|
) |
|
if cmdFiles, err = ioutil.ReadDir(cmdPath); err != nil { |
|
return |
|
} |
|
for _, f := range cmdFiles { |
|
if !strings.HasSuffix(f.Name(), ".toml") { |
|
continue |
|
} |
|
if tomlPath, err = filepath.Rel(filePath, cmdPath); err != nil { |
|
return |
|
} |
|
if tomlPath != "" { |
|
tomlPath = tomlPath + "/" + f.Name() |
|
break |
|
} |
|
} |
|
var ( |
|
filename = strings.Replace(p.Path, ".go", "_test.go", -1) |
|
flag = pathSplit[right+2 : right+3][0] |
|
conf = strings.Join(pathSplit[left:right+2], "/") + "/conf" |
|
impts = strings.Join([]string{`"os"`, `"flag"`, `"testing"`, "\"" + conf + "\""}, "\n\t") |
|
) |
|
if IsService(flag) { |
|
vars = strings.Join([]string{"s *Service"}, "\n\t") |
|
mainFunc = tpTestServiceMain |
|
} else { |
|
vars = strings.Join([]string{"d *Dao"}, "\n\t") |
|
mainFunc = tpTestDaoMain |
|
} |
|
if _, err := os.Stat(filename); os.IsNotExist(err) { |
|
buffer.WriteString(fmt.Sprintf(tpPackage, p.Package)) |
|
buffer.WriteString(fmt.Sprintf(tpImport, impts)) |
|
buffer.WriteString(fmt.Sprintf(tpVar, vars)) |
|
buffer.WriteString(fmt.Sprintf(mainFunc, tomlPath)) |
|
ioutil.WriteFile(filename, buffer.Bytes(), 0644) |
|
} |
|
return |
|
} |
|
|
|
func genInterface(parses []*parse) (err error) { |
|
var ( |
|
parse *parse |
|
pkg = make(map[string]string) |
|
) |
|
for _, parse = range parses { |
|
if strings.Contains(parse.Path, ".intf.go") { |
|
continue |
|
} |
|
dirPath := filepath.Dir(parse.Path) |
|
for _, parseFunc := range parse.Funcs { |
|
if (parseFunc.Method == nil) || |
|
!(parseFunc.Name[0] >= 'A' && parseFunc.Name[0] <= 'Z') { |
|
continue |
|
} |
|
var ( |
|
params string |
|
results string |
|
) |
|
for k, param := range parseFunc.Params { |
|
params += param.K + " " + param.P + param.V |
|
if len(parseFunc.Params) > k+1 { |
|
params += ", " |
|
} |
|
} |
|
for k, res := range parseFunc.Result { |
|
results += res.K + " " + res.P + res.V |
|
if len(parseFunc.Result) > k+1 { |
|
results += ", " |
|
} |
|
} |
|
if len(results) != 0 { |
|
results = "(" + results + ")" |
|
} |
|
pkg[dirPath] += "\t" + fmt.Sprintf(tpIntfcFunc, parseFunc.Name, params, results) |
|
} |
|
} |
|
for k, v := range pkg { |
|
var buffer bytes.Buffer |
|
pathSplit := strings.Split(k, "/") |
|
filename := k + "/" + pathSplit[len(pathSplit)-1] + ".intf.go" |
|
if _, exist := os.Stat(filename); os.IsExist(exist) { |
|
continue |
|
} |
|
buffer.WriteString(fmt.Sprintf(tpPackage, pathSplit[len(pathSplit)-1])) |
|
buffer.WriteString(fmt.Sprintf(tpInterface, strings.Title(pathSplit[len(pathSplit)-1]), v)) |
|
content, _ := GoImport(filename, buffer.Bytes()) |
|
err = ioutil.WriteFile(filename, content, 0644) |
|
} |
|
return |
|
} |
|
|
|
func genMock(files ...string) (err error) { |
|
for _, file := range files { |
|
var pkg *model.Package |
|
if pkg, err = mockgen.ParseFile(file); err != nil { |
|
return |
|
} |
|
if len(pkg.Interfaces) == 0 { |
|
continue |
|
} |
|
var mockDir = pkg.SrcDir + "/mock" |
|
if _, err = os.Stat(mockDir); os.IsNotExist(err) { |
|
err = nil |
|
os.Mkdir(mockDir, 0744) |
|
} |
|
var mockPath = mockDir + "/" + pkg.Name + "_mock.go" |
|
if _, exist := os.Stat(mockPath); os.IsExist(exist) { |
|
continue |
|
} |
|
var g = &mockgen.Generator{Filename: file} |
|
if err = g.Generate(pkg, "mock", mockPath); err != nil { |
|
return |
|
} |
|
if err = ioutil.WriteFile(mockPath, g.Output(), 0644); err != nil { |
|
return |
|
} |
|
} |
|
return |
|
} |
|
|
|
func genMonkey(parses []*parse) (err error) { |
|
var ( |
|
pkg = make(map[string]string) |
|
) |
|
for _, parse := range parses { |
|
if strings.Contains(parse.Path, "monkey.go") || strings.Contains(parse.Path, "/mock/") { |
|
continue |
|
} |
|
var ( |
|
mockVar, mockType, srcDir, flag string |
|
path = strings.Split(filepath.Dir(parse.Path), "/") |
|
pack = ConvertHump(path[len(path)-1]) |
|
refer = path[len(path)-1] |
|
) |
|
for i := len(path) - 1; i > len(path)-4; i-- { |
|
if path[i] == "dao" || path[i] == "service" { |
|
srcDir = strings.Join(path[:i+1], "/") |
|
flag = path[i] |
|
break |
|
} |
|
pack = ConvertHump(path[i-1]) + pack |
|
} |
|
if IsService(flag) { |
|
mockVar = "s" |
|
mockType = "*" + refer + ".Service" |
|
} else { |
|
mockVar = "d" |
|
mockType = "*" + refer + ".Dao" |
|
} |
|
for _, parseFunc := range parse.Funcs { |
|
if (parseFunc.Method == nil) || (parseFunc.Result == nil) || |
|
!(parseFunc.Name[0] >= 'A' && parseFunc.Name[0] <= 'Z') { |
|
continue |
|
} |
|
var ( |
|
funcParams, funcResults, mockKey, mockValue, funcName string |
|
) |
|
funcName = pack + parseFunc.Name |
|
for k, param := range parseFunc.Params { |
|
funcParams += "_ " + param.V |
|
if len(parseFunc.Params) > k+1 { |
|
funcParams += ", " |
|
} |
|
} |
|
for k, res := range parseFunc.Result { |
|
if res.K == "" { |
|
if res.V == "error" { |
|
res.K = "err" |
|
} else { |
|
res.K = fmt.Sprintf("p%d", k+1) |
|
} |
|
} |
|
mockKey += res.K |
|
mockValue += res.V |
|
funcResults += res.K + " " + res.P + res.V |
|
if len(parseFunc.Result) > k+1 { |
|
mockKey += ", " |
|
mockValue += ", " |
|
funcResults += ", " |
|
} |
|
} |
|
pkg[srcDir+"."+refer] += fmt.Sprintf(tpMonkeyFunc, funcName, funcName, mockVar, mockType, funcResults, mockVar, parseFunc.Name, mockType, funcParams, mockValue, mockKey) |
|
} |
|
} |
|
for path, content := range pkg { |
|
var ( |
|
buffer bytes.Buffer |
|
dir = strings.Split(path, ".") |
|
mockDir = dir[0] + "/mock" |
|
filename = mockDir + "/monkey_" + dir[1] + ".go" |
|
) |
|
if _, err = os.Stat(mockDir); os.IsNotExist(err) { |
|
err = nil |
|
os.Mkdir(mockDir, 0744) |
|
} |
|
if _, err := os.Stat(filename); os.IsExist(err) { |
|
continue |
|
} |
|
buffer.WriteString(fmt.Sprintf(tpPackage, "mock")) |
|
buffer.WriteString(content) |
|
content, _ := GoImport(filename, buffer.Bytes()) |
|
ioutil.WriteFile(filename, content, 0644) |
|
} |
|
return |
|
}
|
|
|