ast_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. package test
  2. import (
  3. "io/ioutil"
  4. "testing"
  5. "github.com/stretchr/testify/assert"
  6. "github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
  7. "github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
  8. )
  9. var parser = ast.NewParser(ast.WithParserPrefix("test.api"), ast.WithParserDebug())
  10. func TestApi(t *testing.T) {
  11. fn := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
  12. return p.Api().Accept(visitor)
  13. }
  14. content, err := ioutil.ReadFile("./apis/test.api")
  15. assert.Nil(t, err)
  16. v, err := parser.Accept(fn, string(content))
  17. assert.Nil(t, err)
  18. api := v.(*ast.Api)
  19. body := &ast.Body{
  20. Lp: ast.NewTextExpr("("),
  21. Rp: ast.NewTextExpr(")"),
  22. Name: &ast.Literal{Literal: ast.NewTextExpr("FooBar")},
  23. }
  24. returns := ast.NewTextExpr("returns")
  25. assert.True(t, api.Equal(&ast.Api{
  26. Syntax: &ast.SyntaxExpr{
  27. Syntax: ast.NewTextExpr("syntax"),
  28. Assign: ast.NewTextExpr("="),
  29. Version: ast.NewTextExpr(`"v1"`),
  30. DocExpr: []ast.Expr{
  31. ast.NewTextExpr("// syntax doc"),
  32. },
  33. CommentExpr: ast.NewTextExpr("// syntax comment"),
  34. },
  35. Import: []*ast.ImportExpr{
  36. {
  37. Import: ast.NewTextExpr("import"),
  38. Value: ast.NewTextExpr(`"foo.api"`),
  39. DocExpr: []ast.Expr{
  40. ast.NewTextExpr("// import doc"),
  41. },
  42. CommentExpr: ast.NewTextExpr("// import comment"),
  43. },
  44. {
  45. Import: ast.NewTextExpr("import"),
  46. Value: ast.NewTextExpr(`"bar.api"`),
  47. DocExpr: []ast.Expr{
  48. ast.NewTextExpr("// import group doc"),
  49. },
  50. CommentExpr: ast.NewTextExpr("// import group comment"),
  51. },
  52. },
  53. Info: &ast.InfoExpr{
  54. Info: ast.NewTextExpr("info"),
  55. Lp: ast.NewTextExpr("("),
  56. Rp: ast.NewTextExpr(")"),
  57. Kvs: []*ast.KvExpr{
  58. {
  59. Key: ast.NewTextExpr("author"),
  60. Value: ast.NewTextExpr(`"songmeizi"`),
  61. DocExpr: []ast.Expr{
  62. ast.NewTextExpr("// author doc"),
  63. },
  64. CommentExpr: ast.NewTextExpr("// author comment"),
  65. },
  66. {
  67. Key: ast.NewTextExpr("date"),
  68. Value: ast.NewTextExpr(`2020-01-04`),
  69. DocExpr: []ast.Expr{
  70. ast.NewTextExpr("// date doc"),
  71. },
  72. CommentExpr: ast.NewTextExpr("// date comment"),
  73. },
  74. {
  75. Key: ast.NewTextExpr("desc"),
  76. Value: ast.NewTextExpr(`"break line
  77. desc"`),
  78. DocExpr: []ast.Expr{
  79. ast.NewTextExpr("// desc doc"),
  80. },
  81. CommentExpr: ast.NewTextExpr("// desc comment"),
  82. },
  83. },
  84. },
  85. Type: []ast.TypeExpr{
  86. &ast.TypeStruct{
  87. Name: ast.NewTextExpr("FooBar"),
  88. Struct: ast.NewTextExpr("struct"),
  89. LBrace: ast.NewTextExpr("{"),
  90. RBrace: ast.NewTextExpr("}"),
  91. Fields: []*ast.TypeField{
  92. {
  93. Name: ast.NewTextExpr("Foo"),
  94. DataType: &ast.Literal{Literal: ast.NewTextExpr("int")},
  95. },
  96. },
  97. },
  98. &ast.TypeStruct{
  99. Name: ast.NewTextExpr("Bar"),
  100. LBrace: ast.NewTextExpr("{"),
  101. RBrace: ast.NewTextExpr("}"),
  102. DocExpr: []ast.Expr{
  103. ast.NewTextExpr("// remove struct"),
  104. },
  105. Fields: []*ast.TypeField{
  106. {
  107. Name: ast.NewTextExpr("VString"),
  108. DataType: &ast.Literal{Literal: ast.NewTextExpr("string")},
  109. Tag: ast.NewTextExpr("`json:\"vString\"`"),
  110. DocExpr: []ast.Expr{
  111. ast.NewTextExpr("// vString"),
  112. },
  113. },
  114. {
  115. Name: ast.NewTextExpr("VBool"),
  116. DataType: &ast.Literal{Literal: ast.NewTextExpr("bool")},
  117. Tag: ast.NewTextExpr("`json:\"vBool\"`"),
  118. DocExpr: []ast.Expr{
  119. ast.NewTextExpr("// vBool"),
  120. },
  121. },
  122. {
  123. Name: ast.NewTextExpr("VInt8"),
  124. DataType: &ast.Literal{Literal: ast.NewTextExpr("int8")},
  125. Tag: ast.NewTextExpr("`json:\"vInt8\"`"),
  126. DocExpr: []ast.Expr{
  127. ast.NewTextExpr("// vInt8"),
  128. },
  129. },
  130. {
  131. Name: ast.NewTextExpr("VInt16"),
  132. DataType: &ast.Literal{Literal: ast.NewTextExpr("int16")},
  133. Tag: ast.NewTextExpr("`json:\"vInt16\"`"),
  134. DocExpr: []ast.Expr{
  135. ast.NewTextExpr("// vInt16"),
  136. },
  137. },
  138. {
  139. Name: ast.NewTextExpr("VInt32"),
  140. DataType: &ast.Literal{Literal: ast.NewTextExpr("int32")},
  141. Tag: ast.NewTextExpr("`json:\"vInt32\"`"),
  142. DocExpr: []ast.Expr{
  143. ast.NewTextExpr("// vInt32"),
  144. },
  145. },
  146. {
  147. Name: ast.NewTextExpr("VInt64"),
  148. DataType: &ast.Literal{Literal: ast.NewTextExpr("int64")},
  149. Tag: ast.NewTextExpr("`json:\"vInt64\"`"),
  150. DocExpr: []ast.Expr{
  151. ast.NewTextExpr("// vInt64"),
  152. },
  153. },
  154. {
  155. Name: ast.NewTextExpr("VInt"),
  156. DataType: &ast.Literal{Literal: ast.NewTextExpr("int")},
  157. Tag: ast.NewTextExpr("`json:\"vInt\"`"),
  158. DocExpr: []ast.Expr{
  159. ast.NewTextExpr("// vInt"),
  160. },
  161. },
  162. {
  163. Name: ast.NewTextExpr("VUInt8"),
  164. DataType: &ast.Literal{Literal: ast.NewTextExpr("uint8")},
  165. Tag: ast.NewTextExpr("`json:\"vUInt8\"`"),
  166. DocExpr: []ast.Expr{
  167. ast.NewTextExpr("// vUInt8"),
  168. },
  169. },
  170. {
  171. Name: ast.NewTextExpr("VUInt16"),
  172. DataType: &ast.Literal{Literal: ast.NewTextExpr("uint16")},
  173. Tag: ast.NewTextExpr("`json:\"vUInt16\"`"),
  174. DocExpr: []ast.Expr{
  175. ast.NewTextExpr("// vUInt16"),
  176. },
  177. },
  178. {
  179. Name: ast.NewTextExpr("VUInt32"),
  180. DataType: &ast.Literal{Literal: ast.NewTextExpr("uint32")},
  181. Tag: ast.NewTextExpr("`json:\"vUInt32\"`"),
  182. DocExpr: []ast.Expr{
  183. ast.NewTextExpr("// vUInt32"),
  184. },
  185. },
  186. {
  187. Name: ast.NewTextExpr("VUInt64"),
  188. DataType: &ast.Literal{Literal: ast.NewTextExpr("uint64")},
  189. Tag: ast.NewTextExpr("`json:\"vUInt64\"`"),
  190. DocExpr: []ast.Expr{
  191. ast.NewTextExpr("// vUInt64"),
  192. },
  193. },
  194. {
  195. Name: ast.NewTextExpr("VFloat32"),
  196. DataType: &ast.Literal{Literal: ast.NewTextExpr("float32")},
  197. Tag: ast.NewTextExpr("`json:\"vFloat32\"`"),
  198. DocExpr: []ast.Expr{
  199. ast.NewTextExpr("// vFloat32"),
  200. },
  201. },
  202. {
  203. Name: ast.NewTextExpr("VFloat64"),
  204. DataType: &ast.Literal{Literal: ast.NewTextExpr("float64")},
  205. Tag: ast.NewTextExpr("`json:\"vFloat64\"`"),
  206. DocExpr: []ast.Expr{
  207. ast.NewTextExpr("// vFloat64"),
  208. },
  209. },
  210. {
  211. Name: ast.NewTextExpr("VByte"),
  212. DataType: &ast.Literal{Literal: ast.NewTextExpr("byte")},
  213. Tag: ast.NewTextExpr("`json:\"vByte\"`"),
  214. DocExpr: []ast.Expr{
  215. ast.NewTextExpr("// vByte"),
  216. },
  217. },
  218. {
  219. Name: ast.NewTextExpr("VRune"),
  220. DataType: &ast.Literal{Literal: ast.NewTextExpr("rune")},
  221. Tag: ast.NewTextExpr("`json:\"vRune\"`"),
  222. DocExpr: []ast.Expr{
  223. ast.NewTextExpr("// vRune"),
  224. },
  225. },
  226. {
  227. Name: ast.NewTextExpr("VMap"),
  228. DataType: &ast.Map{
  229. MapExpr: ast.NewTextExpr("map[string]int"),
  230. Map: ast.NewTextExpr("map"),
  231. LBrack: ast.NewTextExpr("["),
  232. RBrack: ast.NewTextExpr("]"),
  233. Key: ast.NewTextExpr("string"),
  234. Value: &ast.Literal{Literal: ast.NewTextExpr("int")},
  235. },
  236. Tag: ast.NewTextExpr("`json:\"vMap\"`"),
  237. DocExpr: []ast.Expr{
  238. ast.NewTextExpr("// vMap"),
  239. },
  240. },
  241. {
  242. Name: ast.NewTextExpr("VArray"),
  243. DataType: &ast.Array{
  244. ArrayExpr: ast.NewTextExpr("[]int"),
  245. LBrack: ast.NewTextExpr("["),
  246. RBrack: ast.NewTextExpr("]"),
  247. Literal: &ast.Literal{Literal: ast.NewTextExpr("int")},
  248. },
  249. Tag: ast.NewTextExpr("`json:\"vArray\"`"),
  250. DocExpr: []ast.Expr{
  251. ast.NewTextExpr("// vArray"),
  252. },
  253. },
  254. {
  255. Name: ast.NewTextExpr("VStruct"),
  256. DataType: &ast.Literal{Literal: ast.NewTextExpr("FooBar")},
  257. Tag: ast.NewTextExpr("`json:\"vStruct\"`"),
  258. DocExpr: []ast.Expr{
  259. ast.NewTextExpr("// vStruct"),
  260. },
  261. },
  262. {
  263. Name: ast.NewTextExpr("VStructPointer"),
  264. DataType: &ast.Pointer{
  265. PointerExpr: ast.NewTextExpr("*FooBar"),
  266. Star: ast.NewTextExpr("*"),
  267. Name: ast.NewTextExpr("FooBar"),
  268. },
  269. Tag: ast.NewTextExpr("`json:\"vStructPointer\"`"),
  270. DocExpr: []ast.Expr{
  271. ast.NewTextExpr("// vStructPointer"),
  272. },
  273. },
  274. {
  275. Name: ast.NewTextExpr("VInterface"),
  276. DataType: &ast.Interface{Literal: ast.NewTextExpr("interface{}")},
  277. Tag: ast.NewTextExpr("`json:\"vInterface\"`"),
  278. DocExpr: []ast.Expr{
  279. ast.NewTextExpr("// vInterface"),
  280. },
  281. },
  282. {
  283. IsAnonymous: true,
  284. DataType: &ast.Literal{Literal: ast.NewTextExpr("FooBar")},
  285. DocExpr: []ast.Expr{
  286. ast.NewTextExpr("// inline"),
  287. },
  288. },
  289. },
  290. },
  291. },
  292. Service: []*ast.Service{
  293. {
  294. AtServer: &ast.AtServer{
  295. AtServerToken: ast.NewTextExpr("@server"),
  296. Lp: ast.NewTextExpr("("),
  297. Rp: ast.NewTextExpr(")"),
  298. Kv: []*ast.KvExpr{
  299. {
  300. Key: ast.NewTextExpr("host"),
  301. Value: ast.NewTextExpr("0.0.0.0"),
  302. },
  303. {
  304. Key: ast.NewTextExpr("port"),
  305. Value: ast.NewTextExpr("8080"),
  306. },
  307. {
  308. Key: ast.NewTextExpr("annotation"),
  309. Value: ast.NewTextExpr(`"break line
  310. desc"`),
  311. },
  312. },
  313. },
  314. ServiceApi: &ast.ServiceApi{
  315. ServiceToken: ast.NewTextExpr("service"),
  316. Name: ast.NewTextExpr("foo-api"),
  317. Lbrace: ast.NewTextExpr("{"),
  318. Rbrace: ast.NewTextExpr("}"),
  319. ServiceRoute: []*ast.ServiceRoute{
  320. {
  321. AtDoc: &ast.AtDoc{
  322. AtDocToken: ast.NewTextExpr("@doc"),
  323. Lp: ast.NewTextExpr("("),
  324. Rp: ast.NewTextExpr(")"),
  325. LineDoc: ast.NewTextExpr(`"foo"`),
  326. },
  327. AtHandler: &ast.AtHandler{
  328. AtHandlerToken: ast.NewTextExpr("@handler"),
  329. Name: ast.NewTextExpr("postFoo"),
  330. },
  331. Route: &ast.Route{
  332. Method: ast.NewTextExpr("post"),
  333. Path: ast.NewTextExpr("/foo"),
  334. Req: body,
  335. ReturnToken: returns,
  336. Reply: body,
  337. DocExpr: []ast.Expr{
  338. ast.NewTextExpr("// foo"),
  339. },
  340. },
  341. },
  342. {
  343. AtDoc: &ast.AtDoc{
  344. AtDocToken: ast.NewTextExpr("@doc"),
  345. Lp: ast.NewTextExpr("("),
  346. Rp: ast.NewTextExpr(")"),
  347. Kv: []*ast.KvExpr{
  348. {
  349. Key: ast.NewTextExpr("summary"),
  350. Value: ast.NewTextExpr("bar"),
  351. },
  352. },
  353. },
  354. AtServer: &ast.AtServer{
  355. AtServerToken: ast.NewTextExpr("@server"),
  356. Lp: ast.NewTextExpr("("),
  357. Rp: ast.NewTextExpr(")"),
  358. Kv: []*ast.KvExpr{
  359. {
  360. Key: ast.NewTextExpr("handler"),
  361. Value: ast.NewTextExpr("postBar"),
  362. },
  363. },
  364. },
  365. Route: &ast.Route{
  366. Method: ast.NewTextExpr("post"),
  367. Path: ast.NewTextExpr("/bar"),
  368. Req: body,
  369. },
  370. },
  371. {
  372. AtDoc: &ast.AtDoc{
  373. AtDocToken: ast.NewTextExpr("@doc"),
  374. Lp: ast.NewTextExpr("("),
  375. Rp: ast.NewTextExpr(")"),
  376. LineDoc: ast.NewTextExpr(`"foobar"`),
  377. },
  378. AtHandler: &ast.AtHandler{
  379. AtHandlerToken: ast.NewTextExpr("@handler"),
  380. Name: ast.NewTextExpr("postFooBar"),
  381. },
  382. Route: &ast.Route{
  383. Method: ast.NewTextExpr("post"),
  384. Path: ast.NewTextExpr("/foo/bar"),
  385. ReturnToken: returns,
  386. Reply: body,
  387. DocExpr: []ast.Expr{
  388. ast.NewTextExpr(`/**
  389. * httpmethod: post
  390. * path: /foo/bar
  391. * reply: FooBar
  392. */`),
  393. },
  394. },
  395. },
  396. {
  397. AtDoc: &ast.AtDoc{
  398. AtDocToken: ast.NewTextExpr("@doc"),
  399. Lp: ast.NewTextExpr("("),
  400. Rp: ast.NewTextExpr(")"),
  401. LineDoc: ast.NewTextExpr(`"barfoo"`),
  402. },
  403. AtHandler: &ast.AtHandler{
  404. AtHandlerToken: ast.NewTextExpr("@handler"),
  405. Name: ast.NewTextExpr("postBarFoo"),
  406. },
  407. Route: &ast.Route{
  408. Method: ast.NewTextExpr("post"),
  409. Path: ast.NewTextExpr("/bar/foo"),
  410. ReturnToken: returns,
  411. Reply: body,
  412. CommentExpr: ast.NewTextExpr("// post:/bar/foo"),
  413. },
  414. },
  415. {
  416. AtDoc: &ast.AtDoc{
  417. AtDocToken: ast.NewTextExpr("@doc"),
  418. Lp: ast.NewTextExpr("("),
  419. Rp: ast.NewTextExpr(")"),
  420. LineDoc: ast.NewTextExpr(`"barfoo"`),
  421. },
  422. AtHandler: &ast.AtHandler{
  423. AtHandlerToken: ast.NewTextExpr("@handler"),
  424. Name: ast.NewTextExpr("getBarFoo"),
  425. },
  426. Route: &ast.Route{
  427. Method: ast.NewTextExpr("get"),
  428. Path: ast.NewTextExpr("/bar/foo"),
  429. ReturnToken: returns,
  430. Reply: body,
  431. },
  432. },
  433. },
  434. },
  435. },
  436. },
  437. }))
  438. }
  439. func TestApiSyntax(t *testing.T) {
  440. fn := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
  441. return p.Api().Accept(visitor)
  442. }
  443. parser.Accept(fn, `
  444. // doc 1
  445. // doc 2
  446. syntax = "v1" // comment 1
  447. // comment 2
  448. import "foo.api"
  449. `)
  450. }