gen.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "github.com/otokaze/mock/mockgen"
  10. "github.com/otokaze/mock/mockgen/model"
  11. )
  12. func genTest(parses []*parse) (err error) {
  13. for _, p := range parses {
  14. switch {
  15. case strings.HasSuffix(p.Path, "_mock.go") ||
  16. strings.HasSuffix(p.Path, ".intf.go"):
  17. continue
  18. case strings.HasSuffix(p.Path, "dao.go") ||
  19. strings.HasSuffix(p.Path, "service.go"):
  20. err = p.genTestMain()
  21. default:
  22. err = p.genUTTest()
  23. }
  24. if err != nil {
  25. break
  26. }
  27. }
  28. return
  29. }
  30. func (p *parse) genUTTest() (err error) {
  31. var (
  32. buffer bytes.Buffer
  33. impts = strings.Join([]string{
  34. `"context"`,
  35. `"testing"`,
  36. `"github.com/smartystreets/goconvey/convey"`,
  37. }, "\n\t")
  38. content []byte
  39. )
  40. filename := strings.Replace(p.Path, ".go", "_test.go", -1)
  41. if _, err = os.Stat(filename); (_func == "" && err == nil) ||
  42. (err != nil && os.IsExist(err)) {
  43. err = nil
  44. return
  45. }
  46. for _, impt := range p.Imports {
  47. impts += "\n\t" + impt
  48. }
  49. if _func == "" {
  50. buffer.WriteString(fmt.Sprintf(tpPackage, p.Package))
  51. buffer.WriteString(fmt.Sprintf(tpImport, impts))
  52. }
  53. for _, parseFunc := range p.Funcs {
  54. if _func != "" && _func != parseFunc.Name {
  55. continue
  56. }
  57. var (
  58. methodK string
  59. tpVars string
  60. vars []string
  61. val []string
  62. notice = "Then "
  63. reset string
  64. )
  65. if parseFunc.Method != nil {
  66. switch {
  67. case strings.Contains(p.Path, "/library"):
  68. methodK = ""
  69. case strings.Contains(p.Path, "/service"):
  70. methodK = "s."
  71. case strings.Contains(p.Path, "/dao"):
  72. methodK = "d."
  73. }
  74. // if IsService(p.Package) {
  75. // methodK = "s."
  76. // } else {
  77. // methodK = "d."
  78. // }
  79. }
  80. tpTestFuncs := fmt.Sprintf(tpTestFunc, strings.Title(p.Package), parseFunc.Name, parseFunc.Name, "%s", "%s", "%s")
  81. tpTestFuncBeCall := methodK + parseFunc.Name + "(%s)\n\t\t\tconvCtx.Convey(\"%s\", func(convCtx convey.C) {"
  82. if parseFunc.Result == nil {
  83. tpTestFuncBeCall = fmt.Sprintf(tpTestFuncBeCall, "%s", "No return values")
  84. tpTestFuncs = fmt.Sprintf(tpTestFuncs, "%s", tpTestFuncBeCall, "%s")
  85. }
  86. for k, res := range parseFunc.Result {
  87. if res.K == "" {
  88. res.K = fmt.Sprintf("p%d", k+1)
  89. }
  90. var so string
  91. if res.V == "error" {
  92. res.K = "err"
  93. so = fmt.Sprintf("\tconvCtx.So(%s, convey.ShouldBeNil)", res.K)
  94. notice += "err should be nil."
  95. } else {
  96. so = fmt.Sprintf("\tconvCtx.So(%s, convey.ShouldNotBeNil)", res.K)
  97. val = append(val, res.K)
  98. }
  99. if len(parseFunc.Result) <= k+1 {
  100. if len(val) != 0 {
  101. notice += strings.Join(val, ",") + " should not be nil."
  102. }
  103. tpTestFuncBeCall = fmt.Sprintf(tpTestFuncBeCall, "%s", notice)
  104. res.K += " := " + tpTestFuncBeCall
  105. } else {
  106. res.K += ", %s"
  107. }
  108. tpTestFuncs = fmt.Sprintf(tpTestFuncs, "%s", res.K+"\n\t\t\t%s", "%s")
  109. tpTestFuncs = fmt.Sprintf(tpTestFuncs, "%s", "%s", so, "%s")
  110. }
  111. if parseFunc.Params == nil {
  112. tpTestFuncs = fmt.Sprintf(tpTestFuncs, "%s", "", "%s")
  113. }
  114. for k, pType := range parseFunc.Params {
  115. if pType.K == "" {
  116. pType.K = fmt.Sprintf("a%d", k+1)
  117. }
  118. var (
  119. init string
  120. params = pType.K
  121. )
  122. switch {
  123. case strings.HasPrefix(pType.V, "context"):
  124. init = params + " = context.Background()"
  125. case strings.HasPrefix(pType.V, "[]byte"):
  126. init = params + " = " + pType.V + "(\"\")"
  127. case strings.HasPrefix(pType.V, "[]"):
  128. init = params + " = " + pType.V + "{}"
  129. case strings.HasPrefix(pType.V, "int") ||
  130. strings.HasPrefix(pType.V, "uint") ||
  131. strings.HasPrefix(pType.V, "float") ||
  132. strings.HasPrefix(pType.V, "double"):
  133. init = params + " = " + pType.V + "(0)"
  134. case strings.HasPrefix(pType.V, "string"):
  135. init = params + " = \"\""
  136. case strings.Contains(pType.V, "*xsql.Tx"):
  137. // init = params + ",_ = d.BeginTran(c)"
  138. init = params + ",_ = " + methodK + "BeginTran(c)"
  139. reset += "\n\t" + params + ".Commit()"
  140. case strings.HasPrefix(pType.V, "*"):
  141. init = params + " = " + strings.Replace(pType.V, "*", "&", -1) + "{}"
  142. case strings.Contains(pType.V, "chan"):
  143. init = params + " = " + pType.V
  144. case pType.V == "time.Time":
  145. init = params + " = time.Now()"
  146. case strings.Contains(pType.V, "chan"):
  147. init = params + " = " + pType.V
  148. default:
  149. init = params + " " + pType.V
  150. }
  151. vars = append(vars, "\t\t"+init)
  152. if len(parseFunc.Params) > k+1 {
  153. params += ", %s"
  154. }
  155. tpTestFuncs = fmt.Sprintf(tpTestFuncs, "%s", params, "%s")
  156. }
  157. if len(vars) > 0 {
  158. tpVars = fmt.Sprintf(tpVar, strings.Join(vars, "\n\t"))
  159. }
  160. tpTestFuncs = fmt.Sprintf(tpTestFuncs, tpVars, "%s")
  161. if reset != "" {
  162. tpTestResets := fmt.Sprintf(tpTestReset, reset)
  163. tpTestFuncs = fmt.Sprintf(tpTestFuncs, tpTestResets)
  164. } else {
  165. tpTestFuncs = fmt.Sprintf(tpTestFuncs, "")
  166. }
  167. buffer.WriteString(tpTestFuncs)
  168. }
  169. var (
  170. file *os.File
  171. flag = os.O_RDWR | os.O_CREATE | os.O_APPEND
  172. )
  173. if file, err = os.OpenFile(filename, flag, 0644); err != nil {
  174. return
  175. }
  176. if _func == "" {
  177. content, _ = GoImport(filename, buffer.Bytes())
  178. } else {
  179. content = buffer.Bytes()
  180. }
  181. if _, err = file.Write(content); err != nil {
  182. return
  183. }
  184. if err = file.Close(); err != nil {
  185. return
  186. }
  187. return
  188. }
  189. func (p *parse) genTestMain() (err error) {
  190. var (
  191. buffer bytes.Buffer
  192. left, right int
  193. vars, mainFunc, fileAbs string
  194. )
  195. if fileAbs, err = filepath.Abs(p.Path); err != nil {
  196. return
  197. }
  198. var pathSplit []string
  199. if pathSplit = strings.Split(fileAbs, "/"); len(pathSplit) == 1 {
  200. pathSplit = strings.Split(fileAbs, "\\")
  201. }
  202. for index, value := range pathSplit {
  203. if value == "go-common" {
  204. left = index
  205. }
  206. if value == "main" ||
  207. value == "ep" ||
  208. value == "openplatform" ||
  209. value == "live" ||
  210. value == "video" ||
  211. value == "tool" ||
  212. value == "bbq" ||
  213. value == "library" {
  214. right = index
  215. break
  216. }
  217. }
  218. var (
  219. tomlPath string
  220. filePath = filepath.Dir(fileAbs)
  221. cmdFiles []os.FileInfo
  222. cmdPath = strings.Join(pathSplit[:right+2], "/") + "/cmd"
  223. )
  224. if cmdFiles, err = ioutil.ReadDir(cmdPath); err != nil {
  225. return
  226. }
  227. for _, f := range cmdFiles {
  228. if !strings.HasSuffix(f.Name(), ".toml") {
  229. continue
  230. }
  231. if tomlPath, err = filepath.Rel(filePath, cmdPath); err != nil {
  232. return
  233. }
  234. if tomlPath != "" {
  235. tomlPath = tomlPath + "/" + f.Name()
  236. break
  237. }
  238. }
  239. var (
  240. filename = strings.Replace(p.Path, ".go", "_test.go", -1)
  241. flag = pathSplit[right+2 : right+3][0]
  242. conf = strings.Join(pathSplit[left:right+2], "/") + "/conf"
  243. impts = strings.Join([]string{`"os"`, `"flag"`, `"testing"`, "\"" + conf + "\""}, "\n\t")
  244. )
  245. if IsService(flag) {
  246. vars = strings.Join([]string{"s *Service"}, "\n\t")
  247. mainFunc = tpTestServiceMain
  248. } else {
  249. vars = strings.Join([]string{"d *Dao"}, "\n\t")
  250. mainFunc = tpTestDaoMain
  251. }
  252. if _, err := os.Stat(filename); os.IsNotExist(err) {
  253. buffer.WriteString(fmt.Sprintf(tpPackage, p.Package))
  254. buffer.WriteString(fmt.Sprintf(tpImport, impts))
  255. buffer.WriteString(fmt.Sprintf(tpVar, vars))
  256. buffer.WriteString(fmt.Sprintf(mainFunc, tomlPath))
  257. ioutil.WriteFile(filename, buffer.Bytes(), 0644)
  258. }
  259. return
  260. }
  261. func genInterface(parses []*parse) (err error) {
  262. var (
  263. parse *parse
  264. pkg = make(map[string]string)
  265. )
  266. for _, parse = range parses {
  267. if strings.Contains(parse.Path, ".intf.go") {
  268. continue
  269. }
  270. dirPath := filepath.Dir(parse.Path)
  271. for _, parseFunc := range parse.Funcs {
  272. if (parseFunc.Method == nil) ||
  273. !(parseFunc.Name[0] >= 'A' && parseFunc.Name[0] <= 'Z') {
  274. continue
  275. }
  276. var (
  277. params string
  278. results string
  279. )
  280. for k, param := range parseFunc.Params {
  281. params += param.K + " " + param.P + param.V
  282. if len(parseFunc.Params) > k+1 {
  283. params += ", "
  284. }
  285. }
  286. for k, res := range parseFunc.Result {
  287. results += res.K + " " + res.P + res.V
  288. if len(parseFunc.Result) > k+1 {
  289. results += ", "
  290. }
  291. }
  292. if len(results) != 0 {
  293. results = "(" + results + ")"
  294. }
  295. pkg[dirPath] += "\t" + fmt.Sprintf(tpIntfcFunc, parseFunc.Name, params, results)
  296. }
  297. }
  298. for k, v := range pkg {
  299. var buffer bytes.Buffer
  300. pathSplit := strings.Split(k, "/")
  301. filename := k + "/" + pathSplit[len(pathSplit)-1] + ".intf.go"
  302. if _, exist := os.Stat(filename); os.IsExist(exist) {
  303. continue
  304. }
  305. buffer.WriteString(fmt.Sprintf(tpPackage, pathSplit[len(pathSplit)-1]))
  306. buffer.WriteString(fmt.Sprintf(tpInterface, strings.Title(pathSplit[len(pathSplit)-1]), v))
  307. content, _ := GoImport(filename, buffer.Bytes())
  308. err = ioutil.WriteFile(filename, content, 0644)
  309. }
  310. return
  311. }
  312. func genMock(files ...string) (err error) {
  313. for _, file := range files {
  314. var pkg *model.Package
  315. if pkg, err = mockgen.ParseFile(file); err != nil {
  316. return
  317. }
  318. if len(pkg.Interfaces) == 0 {
  319. continue
  320. }
  321. var mockDir = pkg.SrcDir + "/mock"
  322. if _, err = os.Stat(mockDir); os.IsNotExist(err) {
  323. err = nil
  324. os.Mkdir(mockDir, 0744)
  325. }
  326. var mockPath = mockDir + "/" + pkg.Name + "_mock.go"
  327. if _, exist := os.Stat(mockPath); os.IsExist(exist) {
  328. continue
  329. }
  330. var g = &mockgen.Generator{Filename: file}
  331. if err = g.Generate(pkg, "mock", mockPath); err != nil {
  332. return
  333. }
  334. if err = ioutil.WriteFile(mockPath, g.Output(), 0644); err != nil {
  335. return
  336. }
  337. }
  338. return
  339. }
  340. func genMonkey(parses []*parse) (err error) {
  341. var (
  342. pkg = make(map[string]string)
  343. )
  344. for _, parse := range parses {
  345. if strings.Contains(parse.Path, "monkey.go") || strings.Contains(parse.Path, "/mock/") {
  346. continue
  347. }
  348. var (
  349. mockVar, mockType, srcDir, flag string
  350. path = strings.Split(filepath.Dir(parse.Path), "/")
  351. pack = ConvertHump(path[len(path)-1])
  352. refer = path[len(path)-1]
  353. )
  354. for i := len(path) - 1; i > len(path)-4; i-- {
  355. if path[i] == "dao" || path[i] == "service" {
  356. srcDir = strings.Join(path[:i+1], "/")
  357. flag = path[i]
  358. break
  359. }
  360. pack = ConvertHump(path[i-1]) + pack
  361. }
  362. if IsService(flag) {
  363. mockVar = "s"
  364. mockType = "*" + refer + ".Service"
  365. } else {
  366. mockVar = "d"
  367. mockType = "*" + refer + ".Dao"
  368. }
  369. for _, parseFunc := range parse.Funcs {
  370. if (parseFunc.Method == nil) || (parseFunc.Result == nil) ||
  371. !(parseFunc.Name[0] >= 'A' && parseFunc.Name[0] <= 'Z') {
  372. continue
  373. }
  374. var (
  375. funcParams, funcResults, mockKey, mockValue, funcName string
  376. )
  377. funcName = pack + parseFunc.Name
  378. for k, param := range parseFunc.Params {
  379. funcParams += "_ " + param.V
  380. if len(parseFunc.Params) > k+1 {
  381. funcParams += ", "
  382. }
  383. }
  384. for k, res := range parseFunc.Result {
  385. if res.K == "" {
  386. if res.V == "error" {
  387. res.K = "err"
  388. } else {
  389. res.K = fmt.Sprintf("p%d", k+1)
  390. }
  391. }
  392. mockKey += res.K
  393. mockValue += res.V
  394. funcResults += res.K + " " + res.P + res.V
  395. if len(parseFunc.Result) > k+1 {
  396. mockKey += ", "
  397. mockValue += ", "
  398. funcResults += ", "
  399. }
  400. }
  401. pkg[srcDir+"."+refer] += fmt.Sprintf(tpMonkeyFunc, funcName, funcName, mockVar, mockType, funcResults, mockVar, parseFunc.Name, mockType, funcParams, mockValue, mockKey)
  402. }
  403. }
  404. for path, content := range pkg {
  405. var (
  406. buffer bytes.Buffer
  407. dir = strings.Split(path, ".")
  408. mockDir = dir[0] + "/mock"
  409. filename = mockDir + "/monkey_" + dir[1] + ".go"
  410. )
  411. if _, err = os.Stat(mockDir); os.IsNotExist(err) {
  412. err = nil
  413. os.Mkdir(mockDir, 0744)
  414. }
  415. if _, err := os.Stat(filename); os.IsExist(err) {
  416. continue
  417. }
  418. buffer.WriteString(fmt.Sprintf(tpPackage, "mock"))
  419. buffer.WriteString(content)
  420. content, _ := GoImport(filename, buffer.Bytes())
  421. ioutil.WriteFile(filename, content, 0644)
  422. }
  423. return
  424. }